scite-ctx.lua /size: 65 Kb    last modification: 2025-02-21 11:03
1-- version   : 1.0.0 - 07/2005 (2008: lua 5.1)
2-- author    : Hans Hagen - PRAGMA ADE - www.pragma-ade.com
3-- copyright : public domain or whatever suits
4-- remark    : part of the context distribution, my first lua code
5
6-- todo: name space for local functions
7-- todo: the spell checking code is for the built-in lexer, the lpeg one uses its own
8
9-- loading: scite-ctx.properties
10
11-- # environment variable
12-- #
13-- #   CTXSPELLPATH=t:/spell
14-- #
15-- # auto language detection
16-- #
17-- #   % version =1.0 language=uk
18-- #   <?xml version='1.0' language='uk' ?>
19
20-- ext.lua.startup.script=$(SciteDefaultHome)/scite-ctx.lua
21--
22-- # extension.$(file.patterns.context)=scite-ctx.lua
23-- # extension.$(file.patterns.example)=scite-ctx.lua
24--
25-- # ext.lua.reset=1
26-- # ext.lua.auto.reload=1
27-- # ext.lua.startup.script=t:/lua/scite-ctx.lua
28--
29-- ctx.menulist.default=\
30--     wrap=wrap_text|\
31--     unwrap=unwrap_text|\
32--     sort=sort_text|\
33--     document=document_text|\
34--     quote=quote_text|\
35--     compound=compound_text|\
36--     check=check_text\|
37--     strip=toggle_strip
38--
39-- ctx.spellcheck.language=auto
40-- ctx.spellcheck.wordsize=4
41-- ctx.spellcheck.wordpath=ENV(CTXSPELLPATH)
42--
43-- ctx.spellcheck.wordfile.all=spell-uk.txt,spell-nl.txt
44--
45-- ctx.spellcheck.wordfile.uk=spell-uk.txt
46-- ctx.spellcheck.wordfile.nl=spell-nl.txt
47-- ctx.spellcheck.wordsize.uk=4
48-- ctx.spellcheck.wordsize.nl=4
49--
50-- command.name.21.*=CTX Action List
51-- command.subsystem.21.*=3
52-- command.21.*=show_menu $(ctx.menulist.default)
53-- command.groupundo.21.*=yes
54-- command.shortcut.21.*=Shift+F11
55--
56-- command.name.22.*=CTX Check Text
57-- command.subsystem.22.*=3
58-- command.22.*=check_text
59-- command.groupundo.22.*=yes
60-- command.shortcut.22.*=Ctrl+L
61--
62-- command.name.23.*=CTX Wrap Text
63-- command.subsystem.23.*=3
64-- command.23.*=wrap_text
65-- command.groupundo.23.*=yes
66-- command.shortcut.23.*=Ctrl+M
67--
68-- # command.21.*=check_text
69-- # command.21.*=dofile e:\context\lua\scite-ctx.lua
70
71-- generic functions
72
73-- Once lpeg is available I will update the functions below.
74
75os.setlocale("C") -- get rid of the locale: it works bad for comparing as in utflen
76
77local props = props or { }
78
79local byte, char = string.byte, string.char
80local lower, upper, format = string.lower, string.upper, string.format
81local gsub, sub, find, rep, match, gmatch = string.gsub, string.sub, string.find, string.rep, string.match, string.gmatch
82local sort, concat = table.sort, table.concat
83local loadstring = loadstring or load
84
85local function check_output_pane()
86    editor.StyleClearAll(output)
87end
88
89-- helpers : utf
90
91local magicstring = rep("<ctx-crlf/>", 2)
92
93local utflen  = utf8 and utf8.len
94local utfchar = utf8 and utf8.char
95
96if not utflen then
97
98    local l2 = char(0xC0)
99    local l3 = char(0xE0)
100    local l4 = char(0xF0)
101
102    utflen = function(str) -- we could use an lpeg instead
103        local n = 0
104        local l = 0
105        for s in gmatch(str,".") do
106            if l > 0 then
107                l = l - 1
108            else
109                n = n + 1
110                if s >= l4 then
111                    l = 3
112                elseif s >= l3 then
113                    l = 2
114                elseif s >= l2 then
115                    l = 1
116                end
117            end
118        end
119        return n
120    end
121
122end
123
124if not utfchar then
125
126    utfchar = function(u)
127        if u <= 0x7F then
128            return char(
129                u
130            )
131        elseif u <= 0x7FF then
132            return char (
133                0xC0 | (u >> 6),
134                0x80 | (u & 0x3F)
135            )
136        elseif u <= 0xFFFF then
137            return char (
138                0xE0 | (u >> 12),
139                0x80 | ((u >> 6) & 0x3F),
140                0x80 | (u & 0x3F)
141            )
142        elseif n < 0x110000 then
143            local n = u - 0x10000
144            local r = ((n & 0xF0000) >> 16) + 1
145            return char (
146                0xF0 | (r >> 2),
147                0x80 | ((r & 3) << 4) | ((n & 0x0F000) >> 12),
148                0x80 | ((n & 0x00FC0) >> 6),
149                0x80 | (n & 0x0003F)
150            )
151        else
152            return utfchar(0xFFFD)
153        end
154    end
155
156end
157
158-- helpers: system
159
160function io.exists(filename)
161    local ok, result, message = pcall(io.open,filename)
162    if result then
163        io.close(result)
164        return true
165    else
166        return false
167    end
168end
169
170local function resultof(command)
171    local handle = io.popen(command,"r") -- already has flush
172    if handle then
173        local result = handle:read("*all") or ""
174        handle:close()
175        return result
176    else
177        return ""
178    end
179end
180
181function os.envvar(str)
182    local s = os.getenv(str)
183    if s ~= '' then
184        return s
185    end
186    s = os.getenv(upper(str))
187    if s ~= '' then
188        return s
189    end
190    s = os.getenv(lower(str))
191    if s ~= '' then
192        return s
193    end
194end
195
196local function loadtable(name)
197    local f = io.open(name,"rb")
198    if f then
199        f:close()
200        return dofile(name)
201    end
202end
203
204-- helpers: reporting
205
206local crlf   = "\n"
207local report = nil
208local trace  = trace
209
210if trace then
211    report = function(fmt,...)
212        if fmt then
213            trace(format(fmt,...))
214        end
215        trace(crlf)
216        io.flush()
217    end
218else
219    trace  = print
220    report = function(fmt,...)
221        if fmt then
222            trace(format(fmt,...))
223        else
224            trace("")
225        end
226        io.flush()
227    end
228end
229
230-- helpers: whatever (old code, we should use our libs)
231
232local function grab(str,delimiter)
233    local list = { }
234    for snippet in gmatch(str,delimiter) do
235        list[#list+1] = snippet
236    end
237    return list
238end
239
240local function expand(str)
241    return (gsub(str,"ENV%((%w+)%)", os.envvar))
242end
243
244local function strip(str)
245    return (gsub(str,"^%s*(.-)%s*$", "%1"))
246end
247
248local function alphasort(list,i)
249    if i and i > 0 then
250        local function alphacmp(a,b)
251            return lower(gsub(sub(a,i),'0',' ')) < lower(gsub(sub(b,i),'0',' '))
252        end
253        sort(list,alphacmp)
254    else
255        local function alphacmp(a,b)
256            return lower(a) < lower(b)
257        end
258        sort(list,alphacmp)
259    end
260end
261
262-- helpers: editor
263
264-- local function column_of_position(position)
265--     local line = editor:LineFromPosition(position)
266--     local oldposition = editor.CurrentPos
267--     local column = 0
268--     editor:GotoPos(position)
269--     while editor.CurrentPos ~= 0 and line == editor:LineFromPosition(editor.CurrentPos) do
270--         editor:CharLeft()
271--         column = column + 1
272--     end
273--     editor:GotoPos(oldposition)
274--     if line > 0 then
275--         return column -1
276--     else
277--         return column
278--     end
279-- end
280
281-- local function line_of_position(position)
282--     return editor:LineFromPosition(position)
283-- end
284
285local function extend_to_start()
286    local selectionstart = editor.SelectionStart
287    local selectionend = editor.SelectionEnd
288    local line = editor:LineFromPosition(selectionstart)
289    if line > 0 then
290        while line == editor:LineFromPosition(selectionstart-1) do
291            selectionstart = selectionstart - 1
292            editor:SetSel(selectionstart,selectionend)
293        end
294    else
295        selectionstart = 0
296    end
297    editor:SetSel(selectionstart,selectionend)
298    return selectionstart
299end
300
301local function extend_to_end() -- editor:LineEndExtend() does not work
302    local selectionstart = editor.SelectionStart
303    local selectionend = editor.SelectionEnd
304    local line = editor:LineFromPosition(selectionend)
305    while line == editor:LineFromPosition(selectionend+1) do
306        selectionend = selectionend + 1
307        editor:SetSel(selectionstart,selectionend)
308        if selectionend ~= editor.SelectionEnd then
309            break -- no progress
310        end
311    end
312    editor:SetSel(selectionstart,selectionend)
313    return selectionend
314end
315
316local function getfiletype()
317    local language = gsub(props.Language or "","script_","")
318    if language ~= "" then
319        return language
320    else
321        local firstline = editor:GetLine(0) or ""
322        if find(firstline,"^%%") then
323            return 'tex'
324        elseif find(firstline,"^<%?xml") then
325            return 'xml'
326        else
327            return 'unknown'
328        end
329    end
330end
331
332-- inspired by LuaExt's scite_Files
333
334-- local function get_dir_list(mask)
335--     local f
336--     if props['PLAT_GTK'] and props['PLAT_GTK'] ~= "" then
337--         f = io.popen('ls -1 ' .. mask)
338--     else
339--         mask = gsub(mask,'/','\\')
340--         local tmpfile = 'scite-ctx.tmp'
341--         local cmd = 'dir /b "' .. mask .. '" > ' .. tmpfile
342--         os.execute(cmd)
343--         f = io.open(tmpfile)
344--     end
345--     local files = { }
346--     if not f then -- path check added
347--         return files
348--     end
349--     for line in f:lines() do
350--         files[#files+1] = line
351--     end
352--     f:close()
353--     return files
354-- end
355
356--helpers : utf from editor
357
358local cat -- has to be set to editor.CharAt
359
360local function toutfcode(pos) -- if needed we can cache
361    local c1 = cat[pos]
362    if c1 < 0 then
363        c1 = 256 + c1
364    end
365    if c1 < 128 then
366        return c1, 1
367    end
368    if c1 < 224 then
369        local c2 = cat[pos+1]
370        if c2 < 0 then
371            c2 = 256 + c2
372        end
373        return c1 * 64 + c2 - 12416, 2
374    end
375    if c1 < 240 then
376        local c2 = cat[pos+1]
377        local c3 = cat[pos+2]
378        if c2 < 0 then
379            c2 = 256 + c2
380        end
381        if c3 < 0 then
382            c3 = 256 + c3
383        end
384        return (c1 * 64 + c2) * 64 + c3 - 925824, 3
385    end
386    if c1 < 245 then
387        local c2 = cat[pos+1]
388        local c3 = cat[pos+2]
389        local c4 = cat[pos+3]
390        if c2 < 0 then
391            c2 = 256 + c2
392        end
393        if c3 < 0 then
394            c3 = 256 + c3
395        end
396        if c4 < 0 then
397            c4 = 256 + c4
398        end
399        return ((c1 * 64 + c2) * 64 + c3) * 64 + c4 - 63447168, 4
400    end
401end
402
403-- banner
404
405do
406
407    check_output_pane()
408
409    print("Some CTX extensions:")
410
411    local wraplength = props['ctx.wraptext.length']
412
413    if wraplength and wraplength ~= "" then
414        print("\n-  ctx.wraptext.length is set to " .. wraplength)
415    else
416        print("\n-  ctx.wraptext.length is not set")
417    end
418
419    local helpinfo = props['ctx.helpinfo']
420
421    if helpinfo and helpinfo ~= "" then
422        print("\n-  key bindings:\n")
423        print((gsub(strip(helpinfo),"%s*|%s*","\n")))
424    else
425        print("\n-  no extra key bindings")
426    end
427
428    print("\n-  recognized first lines:\n")
429    print("xml   <?xml version='1.0' language='..'")
430    print("tex   % language=..")
431    print(" ")
432    print("(lexing is currently being upgraded / improved / made more native to scite)")
433    print(" ")
434
435end
436
437-- text functions
438
439-- written while listening to Talk Talk
440
441function wrap_text()
442
443    -- We always go to the end of a line, so in fact some of
444    -- the variables set next are not needed.
445
446    local length = props["ctx.wraptext.length"]
447
448    if length == '' then length = 80 else length = tonumber(length) end
449
450    local startposition = editor.SelectionStart
451    local endposition   = editor.SelectionEnd
452
453    if startposition == endposition then return end
454
455    editor:LineEndExtend()
456
457    startposition = editor.SelectionStart
458    endposition   = editor.SelectionEnd
459
460    -- local startline   = line_of_position(startposition)
461    -- local endline     = line_of_position(endposition)
462    -- local startcolumn = column_of_position(startposition)
463    -- local endcolumn   = column_of_position(endposition)
464    --
465    -- editor:SetSel(startposition,endposition)
466
467    local startline   = props['SelectionStartLine']
468    local endline     = props['SelectionEndLine']
469    local startcolumn = props['SelectionStartColumn'] - 1
470    local endcolumn   = props['SelectionEndColumn'] - 1
471
472    local replacement = { }
473    local templine    = ''
474    local tempsize    = 0
475    local indentation = rep(' ',startcolumn)
476    local selection   = editor:GetSelText()
477
478    selection = gsub(selection,"[\n\r][\n\r]","\n")
479    selection = gsub(selection,"\n\n+",' ' .. magicstring .. ' ')
480    selection = gsub(selection,"^%s",'')
481
482    for snippet in gmatch(selection,"%S+") do
483        if snippet == magicstring then
484            replacement[#replacement+1] = templine
485            replacement[#replacement+1] = ""
486            templine = ''
487            tempsize = 0
488        else
489            local snipsize = utflen(snippet)
490            if tempsize + snipsize > length then
491                replacement[#replacement+1] = templine
492                templine = indentation .. snippet
493                tempsize = startcolumn + snipsize
494            elseif tempsize == 0 then
495                templine = indentation .. snippet
496                tempsize = tempsize + startcolumn + snipsize
497            else
498                templine = templine .. ' ' .. snippet
499                tempsize = tempsize + 1 + snipsize
500            end
501        end
502    end
503
504    replacement[#replacement+1] = templine
505    replacement[1] = gsub(replacement[1],"^%s+",'')
506
507    if endcolumn == 0 then
508        replacement[#replacement+1] = ""
509    end
510
511    editor:ReplaceSel(concat(replacement,"\n"))
512
513end
514
515function unwrap_text()
516
517    local startposition = editor.SelectionStart
518    local endposition   = editor.SelectionEnd
519
520    if startposition == endposition then return end
521
522    editor:HomeExtend()
523    editor:LineEndExtend()
524
525    startposition = editor.SelectionStart
526    endposition   = editor.SelectionEnd
527
528    local magicstring = rep("<multiplelines/>", 2)
529    local selection   = gsub(editor:GetSelText(),"[\n\r][\n\r]+", ' ' .. magicstring .. ' ')
530    local replacement = ''
531
532    for snippet in gmatch(selection,"%S+") do
533        if snippet == magicstring then
534            replacement = replacement .. "\n"
535        else
536            replacement = replacement .. snippet .. "\n"
537        end
538    end
539
540    if endcolumn == 0 then replacement = replacement .. "\n" end
541
542    editor:ReplaceSel(replacement)
543
544end
545
546function sort_text()
547
548    local startposition = editor.SelectionStart
549    local endposition   = editor.SelectionEnd
550
551    if startposition == endposition then return end
552
553    -- local startcolumn = column_of_position(startposition)
554    -- local endcolumn   = column_of_position(endposition)
555    --
556    -- editor:SetSel(startposition,endposition)
557
558    local startline   = props['SelectionStartLine']
559    local endline     = props['SelectionEndLine']
560    local startcolumn = props['SelectionStartColumn'] - 1
561    local endcolumn   = props['SelectionEndColumn']   - 1
562
563    startposition = extend_to_start()
564    endposition   = extend_to_end()
565
566    local selection = gsub(editor:GetSelText(), "%s*$", '')
567    local list = grab(selection,"[^\n\r]+")
568    alphasort(list, startcolumn)
569    local replacement = concat(list, "\n")
570
571    editor:GotoPos(startposition)
572    editor:SetSel(startposition,endposition)
573
574    if endcolumn == 0 then replacement = replacement .. "\n" end
575
576    editor:ReplaceSel(replacement)
577
578end
579
580do
581
582    local data = {
583        xml = {
584            pattern = "%<%!%-%-.-%-%-%>"
585        },
586        tex = {
587            pattern = "%%.-[\r\n]"
588        },
589    }
590
591    function remove_comment()
592        local filetype  = getfiletype()
593        local filedata  = data[filetype]
594        local selection = editor:GetSelText()
595        if filedata and selection ~= "" then
596            local startposition = editor.SelectionStart
597            local endposition   = editor.SelectionEnd
598            selection = gsub(selection,filedata.pattern,"")
599            selection = gsub(selection,"%s+","")
600            editor:ReplaceSel(selection)
601        end
602    end
603
604end
605
606do
607
608    -- I really needed we can do version numbers but no one uses them.
609
610    local patterns = {
611        "(%d+)%s+(%d+)%s+obj",
612        "(%d+)%s+(%d+)%s+R",
613    }
614
615    local function show_pdf_object(n)
616        local name = props.FilePath
617        local data = resultof("mtxrun --script pdf --object=" .. n .. " " .. name)
618        print(format("file: %s, object number: %s, object data:\n",name,n))
619        print(data)
620    end
621
622    function filter_pdf_object()
623        local filetype  = getfiletype()
624        local selection = editor:GetSelText()
625        if filetype == "pdf" and selection ~= 0 then
626            local n, m
627            for i=1,#patterns do
628                n, m = match(selection,patterns[i])
629                if n and m then
630                    break
631                end
632            end
633            n = tonumber(n)
634            m = tonumber(m)
635            if n and m then
636                show_pdf_object(n)
637            end
638        end
639    end
640
641    function search_pdf_object()
642        local filetype  = getfiletype()
643        local selection = editor:GetSelText()
644        if filetype == "pdf" and selection ~= 0 then
645            local onstrip = OnStrip
646            function OnStrip(control,change)
647                if control == 2 then
648                    local n = tonumber(scite.StripValue(1))
649                    if n then
650                        show_pdf_object(n)
651                    end
652                    OnStrip = onstrip
653                    scite.StripShow("")
654                end
655            end
656            scite.StripShow("!'Object Number:'{}(&Search)\n")
657        end
658    end
659
660end
661
662do
663
664    local valid = {
665        xml = true,
666        tex = true,
667    }
668
669    function document_text()
670        local filetype = getfiletype()
671        if valid[filetype or ""] then
672            local startposition = editor.SelectionStart
673            local endposition   = editor.SelectionEnd
674            if startposition ~= endposition then
675                startposition = extend_to_start()
676                endposition   = extend_to_end()
677                editor:SetSel(startposition,endposition)
678                local replacement = ''
679                for i = editor:LineFromPosition(startposition), editor:LineFromPosition(endposition) do
680                    local str = editor:GetLine(i)
681                    if filetype == 'xml' then
682                        if find(str,"^<%!%-%- .* %-%->%s*$") then
683                            replacement = replacement .. gsub(str,"^<%!%-%- (.*) %-%->(%s*)$","%1\n")
684                        elseif find(str,"%S") then
685                            replacement = replacement .. '<!-- ' .. gsub(str,"(%s*)$",'') .. " -->\n"
686                        else
687                            replacement = replacement .. str
688                        end
689                    else
690                        if find(str,"^%%D%s+$") then
691                            replacement = replacement .. "\n"
692                        elseif find(str,"^%%D ") then
693                            replacement = replacement .. gsub(str,"^%%D ",'')
694                        else
695                            replacement = replacement .. '%D ' .. str
696                        end
697                    end
698                end
699                replacement = gsub(replacement,"[\n\r]$",'')
700                editor:ReplaceSel(replacement)
701            end
702        end
703    end
704
705end
706
707do
708
709    local data = {
710        xml = {
711            quote = {
712                left  = "<quote>",
713                right = "</quote>",
714            },
715            quotation = {
716                left  = "<quotation>",
717                right = "</quotation>",
718            },
719        },
720        tex = {
721            quote = {
722                left  = "\\quote {",
723                right = "}",
724            },
725            quotation = {
726                left  = "\\quotation {",
727                right = "}",
728            },
729        },
730    }
731
732    function quote_text()
733        local filetype  = getfiletype()
734        local filedata  = data[filetype]
735        local selection = editor:GetSelText()
736        if filedata and selection ~= "" then
737            selection = gsub(selection,[["(.-)"]], filedata.quotation.left .. "%1" .. filedata.quotation.right)
738            selection = gsub(selection,[['(.-)']], filedata.quote    .left .. "%1" .. filedata.quote    .right)
739            editor:ReplaceSel(selection)
740        end
741    end
742
743    function quote_text_s()
744        local filetype  = getfiletype()
745        local filedata  = data[filetype]
746        local selection = editor:GetSelText()
747        if filedata and selection ~= "" then
748            selection = filedata.quote.left .. selection .. filedata.quote.right
749            editor:ReplaceSel(selection)
750        end
751    end
752
753    function quote_text_d()
754        local filetype  = getfiletype()
755        local filedata  = data[filetype]
756        local selection = editor:GetSelText()
757        if filedata and selection ~= "" then
758            selection = filedata.quotation.left .. selection .. filedata.quotation.right
759            editor:ReplaceSel(selection)
760        end
761    end
762
763end
764
765do
766
767    local data = {
768        xml = {
769            pattern     = [[(>[^<%-][^<%-]+)([-/])(%w%w+)]],
770            replacement = [[%1<compound token="%2"/>%3]],
771        },
772        tex = {
773            pattern     = [[([^|])([-/]+)([^|])]],
774            replacement = [[%1|%2|%3]],
775        },
776    }
777
778    function compound_text()
779
780        local filetype  = getfiletype()
781        local filedata  = data[filetype]
782        local selection = editor:GetSelText()
783        if filedata and selection ~= "" then
784            selection = gsub(selection,filedata.pattern,filedata.replacement)
785            editor:ReplaceSel(selection)
786        end
787
788    end
789
790end
791
792-- There used to be some spell checking code here usign regular Scite
793-- mechanisms but that has been moved to the lexer code already a while
794-- ago so I removed the (pre 2005) code here. (See archive.)
795
796do
797
798    function add_text()
799
800        local startposition = editor.SelectionStart
801        local endposition   = editor.SelectionEnd
802
803        if startposition == endposition then return end
804
805        local selection = gsub(editor:GetSelText(), "%s*$", '')
806
807        local n, sum = 0, 0
808        for s in gmatch(selection,"[%-%+]?[%d%.%,]+") do -- todo: proper lpeg
809            local s = gsub(s,",",".")
810            local m = tonumber(s)
811            if m then
812                n = n + 1
813                sum = sum + m
814                report("%4i : %s",n,m)
815            end
816        end
817        if n > 0 then
818            report()
819            report("sum  : %s",sum)
820        else
821            report("no numbers selected")
822        end
823
824    end
825
826end
827
828local dirty = { } do
829
830    local bidi = nil
831
832    local mapping = {
833        l   = 0, -- "Left-to-Right",
834        lre = 7, -- "Left-to-Right Embedding",
835        lro = 7, -- "Left-to-Right Override",
836        r   = 2, -- "Right-to-Left",
837        al  = 3, -- "Right-to-Left Arabic",
838        rle = 7, -- "Right-to-Left Embedding",
839        rlo = 7, -- "Right-to-Left Override",
840        pdf = 7, -- "Pop Directional Format",
841        en  = 4, -- "European Number",
842        es  = 4, -- "European Number Separator",
843        et  = 4, -- "European Number Terminator",
844        an  = 5, -- "Arabic Number",
845        cs  = 6, -- "Common Number Separator",
846        nsm = 6, -- "Non-Spacing Mark",
847        bn  = 7, -- "Boundary Neutral",
848        b   = 0, -- "Paragraph Separator",
849        s   = 7, -- "Segment Separator",
850        ws  = 0, -- "Whitespace",
851        on  = 7, -- "Other Neutrals",
852    }
853
854    -- todo: take from scite-context-theme.lua
855
856    local colors = { -- b g r
857        [0] = 0x000000, -- black
858        [1] = 0x00007F, -- red
859        [2] = 0x007F00, -- green
860        [3] = 0x7F0000, -- blue
861        [4] = 0x7F7F00, -- cyan
862        [5] = 0x7F007F, -- magenta
863        [6] = 0x007F7F, -- yellow
864        [7] = 0x007FB0, -- orange
865        [8] = 0x4F4F4F, -- dark
866    }
867
868    -- in principle, when we could inject some funny symbol that is not part of the
869    -- stream and/or use a different extra styling for each snippet then selection
870    -- would work and rendering would look better too ... one problem is that a font
871    -- rendering can collapse characters due to font features
872
873    function show_bidi()
874
875        cat = editor.CharAt
876
877        editor.CodePage = SC_CP_UTF8
878
879        for i=1,#colors do -- 0,#colors
880           editor.StyleFore[i] = colors[i] -- crashes
881        end
882
883        if not bidi then
884            bidi = require("context.scite-ctx-bidi")
885        end
886
887        local len = editor.TextLength
888        local str = editor:textrange(0,len-1)
889
890        local t = { }
891        local a = { }
892        local n = 0
893        local i = 0
894
895        local v
896        while i < len do
897            n = n + 1
898            v, s = toutfcode(i)
899            t[n] = v
900            a[n] = s
901            i = i + s
902        end
903
904        local t = bidi.process(t)
905
906        editor:StartStyling(0,31)
907
908        local defaultcolor = mapping.l
909        local mirrorcolor  = 1
910
911        if false then
912            for i=1,n do
913                local direction = t[i].direction
914                local color     = direction and (mapping[direction] or 0) or defaultcolor
915                editor:SetStyling(a[i],color)
916            end
917        else
918            local lastcolor = -1
919            local runlength = 0
920            for i=1,n do
921                local ti = t[i]
922                local direction = ti.direction
923                local mirror    = t[i].mirror
924                local color     = (mirror and mirrorcolor) or (direction and mapping[direction]) or defaultcolor
925                if color == lastcolor then
926                    runlength = runlength + a[i]
927                else
928                    if runlength > 0 then
929                        editor:SetStyling(runlength,lastcolor)
930                    end
931                    lastcolor = color
932                    runlength = a[i]
933                end
934            end
935            if runlength > 0 then
936                editor:SetStyling(runlength,lastcolor)
937            end
938        end
939
940        editor:SetStyling(2,31)
941
942        dirty[props.FileNameExt] = true
943
944    end
945
946end
947
948-- menu
949
950local menuactions   = { }
951local menufunctions = { }
952local menuentries   = { }
953
954function UserListShow(menutrigger, menulist)
955    if type(menulist) == "string" then
956        menuentries = { }
957        menuactions = { }
958        for item in gmatch(menulist,"[^%|]+") do
959            if item ~= "" then
960                -- why not just a split
961                for key, value in gmatch(item,"%s*(.+)=(.+)%s*") do
962                    menuentries[#menuentries+1] = key
963                    menuactions[key] = value
964                end
965            end
966        end
967    else
968        menuentries = menulist
969        menuactions = false
970    end
971    local menustring = concat(menuentries,'|')
972    if menustring == "" then
973        report("there are no (further) options defined for this file type")
974    else
975        editor.AutoCSeparator = byte('|')
976        editor:UserListShow(menutrigger,menustring)
977        editor.AutoCSeparator = byte(' ')
978    end
979end
980
981function OnUserListSelection(trigger,choice)
982    if menufunctions[trigger] then
983        return menufunctions[trigger](menuactions and menuactions[choice] or choice)
984    else
985        return false
986    end
987end
988
989-- main menu
990
991do
992
993    local menutrigger = 12
994
995    function show_menu(menulist)
996        UserListShow(menutrigger, menulist)
997    end
998
999    function process_menu(action)
1000        if not find(action,"%(%)$") then
1001            assert(load(action .. "()"))()
1002        else
1003            assert(load(action))()
1004        end
1005    end
1006
1007    menufunctions[12] = process_menu
1008
1009end
1010
1011-- The template code is old but used so we cannot drop it. I will cook up a better
1012-- system some day, using Lua tables instead.
1013
1014do
1015
1016    -- <?context-directive job ctxtemplate demotemplate.lua ?>
1017
1018    local templatetrigger = 13
1019
1020    local ctx_template_file = "scite-ctx-templates.lua"
1021    local ctx_template_list = { }
1022    local ctx_template_menu = { }
1023
1024 -- function ctx_list_loaded(path)
1025 --     return ctx_path_list[path] and #ctx_path_list[path] > 0
1026 -- end
1027
1028    local patterns = {
1029        xml = "<%?context%-directive job ctxtemplate (.-) %?>"
1030    }
1031
1032    local function loadtemplate(name)
1033        local temp = gsub(name,"\\","/")
1034        local okay = loadtable(temp)
1035        if okay then
1036            print("template loaded: " .. name)
1037        end
1038        return okay
1039    end
1040
1041    local function loadtemplatefrompaths(path,name)
1042        return loadtemplate(path ..       "/" .. name) or
1043               loadtemplate(path ..    "/../" .. name) or
1044               loadtemplate(path .. "/../../" .. name)
1045    end
1046
1047    function insert_template(templatelist)
1048        local path   = props["FileDir"]
1049        local suffix = props["FileExt"]
1050        local list   = ctx_template_list[path]
1051        if list == nil then
1052            local pattern = patterns[suffix]
1053            local okay    = false
1054            if pattern then
1055                for i=0,9 do
1056                    local line = editor:GetLine(i) or ""
1057                    local name = match(line,pattern)
1058                    if name then
1059                        okay = loadtemplatefrompaths(path,name)
1060                        if not okay then
1061                            name = resultof("mtxrun --find-file " .. name)
1062                            if name then
1063                                name = gsub(name,"\n","")
1064                                okay = loadtemplate(name)
1065                            end
1066                        end
1067                        break
1068                    end
1069                end
1070            end
1071            if not okay then
1072                okay = loadtemplatefrompaths(path,ctx_template_file)
1073            end
1074            if not okay then
1075                okay = loadtemplate(props["SciteDefaultHome"] .. "/context/" .. ctx_template_file)
1076            end
1077            if okay then
1078                list = okay
1079            else
1080                list = false
1081                print("no template file found")
1082            end
1083            ctx_template_list[path] = list
1084        end
1085        ctx_template_menu = { }
1086        if list then
1087            local okay = list[suffix]
1088            if okay then
1089                local menu = { }
1090                for i=1,#okay do
1091                    local o = okay[i]
1092                    local n = o.name
1093                    menu[#menu+1] = n
1094                    ctx_template_menu[n] = o
1095                end
1096                UserListShow(templatetrigger, menu, true)
1097            end
1098        end
1099    end
1100
1101    function inject_template(action)
1102        if ctx_template_menu then
1103            local a = ctx_template_menu[action]
1104            if a then
1105                local template = a.template
1106                local nature   = a.nature
1107                if template then
1108                    local margin = props['SelectionStartColumn'] - 1
1109                 -- template = gsub(template,"\\n","\n")
1110                    template = gsub(template,"%?%?","_____")
1111                    local pos = find(template,"%?")
1112                    template = gsub(template,"%?","")
1113                    template = gsub(template,"_____","?")
1114                    if nature == "display" then
1115                        local spaces = rep(" ",margin)
1116                        if not find(template,"\n$") then
1117                            template = template .. "\n"
1118                        end
1119                        template = gsub(template,"\n",function(s)
1120                            return "\n" .. spaces
1121                        end)
1122                        pos = pos + margin -- todo: check for first line
1123                    end
1124                    editor:insert(editor.CurrentPos,template)
1125                    if pos then
1126                        editor.CurrentPos = editor.CurrentPos + pos - 1
1127                        editor.SelectionStart = editor.CurrentPos
1128                        editor.SelectionEnd = editor.CurrentPos
1129                        editor:GotoPos(editor.CurrentPos)
1130                    end
1131                end
1132            end
1133        end
1134    end
1135
1136    menufunctions[13] = inject_template
1137
1138end
1139
1140do
1141
1142    -- These will become external and taken from sort-lan.lua in the
1143    -- ConTeXt distribution.
1144
1145    local textlists = {
1146        en = {
1147            "a", "b", "c", "d", "e", "f", "g", "h", "i", "j",
1148            "k", "l", "m", "n", "o", "p", "q", "r", "s", "t",
1149            "u", "v", "w", "x", "y", "z",
1150
1151            "A", "B", "C", "D", "E", "F", "G", "H", "I", "J",
1152            "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T",
1153            "U", "V", "W", "X", "Y", "Z",
1154        },
1155        nl = {
1156            "a", "b", "c", "d", "e", "f", "g", "h", "i", "j",
1157            "k", "l", "m", "n", "o", "p", "q", "r", "s", "t",
1158            "u", "v", "w", "x", "y", "z",
1159
1160            "A", "B", "C", "D", "E", "F", "G", "H", "I", "J",
1161            "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T",
1162            "U", "V", "W", "X", "Y", "Z",
1163        },
1164        fr = {
1165            "a", "รฆ", "b", "c", "รง", "d", "e", "รจ", "รฉ", "รช",
1166            "f", "g", "h", "i", "j", "k", "l", "m", "n", "o",
1167            "p", "q", "r", "s", "t", "u", "v", "w", "x", "y",
1168            "z",
1169
1170            "A", "ร†", "B", "C", "ร‡", "D", "E", "รˆ", "ร‰", "รŠ",
1171            "F", "G", "H", "I", "J", "K", "L", "M", "N", "O",
1172            "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y",
1173            "Z",
1174
1175        },
1176        de = {
1177            "a", "รค", "b", "c", "d", "e", "f", "g", "h", "i",
1178            "j", "k", "l", "m", "n", "o", "รถ", "p", "q", "r",
1179            "s", "รŸ", "t", "u", "รผ", "v", "w", "x", "y", "z",
1180
1181            "A", "ร„", "B", "C", "D", "E", "F", "G", "H", "I",
1182            "J", "K", "L", "M", "N", "O", "ร–", "P", "Q", "R",
1183            "S", "SS", "T", "U", "รœ", "V", "W", "X", "Y", "Z",
1184        },
1185        fi = { -- finish
1186            "a", "b", "c", "d", "e", "f", "g", "h", "i", "j",
1187            "k", "l", "m", "n", "o", "p", "q", "r", "s", "t",
1188            "u", "v", "w", "x", "y", "z", "รฅ", "รค", "รถ",
1189
1190            "A", "B", "C", "D", "E", "F", "G", "H", "I", "J",
1191            "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T",
1192            "U", "V", "W", "X", "Y", "Z", "ร…", "ร„", "ร–",
1193        },
1194        sl = { -- slovenian
1195            "a", "b", "c", "ฤ", "ฤ‡", "d", "ฤ‘", "e", "f", "g", "h", "i",
1196            "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "ลก", "t",
1197            "u", "v", "w", "x", "y", "z", "ลพ",
1198
1199            "A", "B", "C", "ฤŒ", "ฤ†", "D", "ฤ", "E", "F", "G", "H", "I",
1200            "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "ล ", "T",
1201            "U", "V", "W", "X", "Y", "Z", "ลฝ",
1202        },
1203        ru = { -- rusian
1204            "ะฐ", "ะฑ", "ะฒ", "ะณ", "ะด", "ะต", "ั‘", "ะถ", "ะท", "ะธ",
1205            "ั–", "ะน", "ะบ", "ะป", "ะผ", "ะฝ", "ะพ", "ะฟ", "ั€", "ั",
1206            "ั‚", "ัƒ", "ั„", "ั…", "ั†", "ั‡", "ัˆ", "ั‰", "ัŠ", "ั‹",
1207            "ัŒ", "ัฃ", "ั", "ัŽ", "ั", "ัณ", "ัต",
1208
1209            "ะ", "ะ‘", "ะ’", "ะ“", "ะ”", "ะ•", "ะ", "ะ–", "ะ—", "ะ˜",
1210            "ะ†", "ะ™", "ะš", "ะ›", "ะœ", "ะ", "ะž", "ะŸ", "ะ ", "ะก",
1211            "ะข", "ะฃ", "ะค", "ะฅ", "ะฆ", "ะง", "ะจ", "ะฉ", "ะช", "ะซ",
1212            "ะฌ", "ัข", "ะญ", "ะฎ", "ะฏ", "ัฒ", "ัด",
1213        },
1214        uk = { -- ukraninuan
1215            "ะฐ", "ะฑ", "ะฒ", "ะณ", "า‘", "ะด", "ะต", "ั”", "ะถ", "ะท", "ะธ", "ั–",
1216            "ั—", "ะน", "ะบ", "ะป", "ะผ", "ะฝ", "ะพ", "ะฟ", "ั€", "ั", "ั‚", "ัƒ",
1217            "ั„", "ั…", "ั†", "ั‡", "ัˆ", "ั‰", "ัŒ", "ัŽ", "ั",
1218
1219            "ะ", "ะ‘", "ะ’", "ะ“", "า", "ะ”", "ะ•", "ะ„", "ะ–", "ะ—", "ะ˜", "ะ†",
1220            "ะ‡", "ะ™", "ะš", "ะ›", "ะœ", "ะ", "ะž", "ะŸ", "ะ ", "ะก", "ะข", "ะฃ",
1221            "ะค", "ะฅ", "ะฆ", "ะง", "ะจ", "ะฉ", "ะฌ", "ะฎ", "ะฏ",
1222        },
1223        be = { -- belarusia
1224            "ะฐ", "ะฑ", "ะฒ", "ะณ", "ะด", "ะต", "ั‘", "ะถ", "ะท", "ั–",
1225            "ะน", "ะบ", "ะป", "ะผ", "ะฝ", "ะพ", "ะฟ", "ั€", "ั", "ั‚",
1226            "ัƒ", "ัž", "ั„", "ั…", "ั†", "ั‡", "ัˆ", "ั‹", "ัŒ", "ั",
1227            "ัŽ", "ั",
1228
1229            "ะ", "ะ‘", "ะ’", "ะ“", "ะ”", "ะ•", "ะ", "ะ–", "ะ—", "ะ†",
1230            "ะ™", "ะš", "ะ›", "ะœ", "ะ", "ะž", "ะŸ", "ะ ", "ะก", "ะข",
1231            "ะฃ", "ะŽ", "ะค", "ะฅ", "ะฆ", "ะง", "ะจ", "ะซ", "ะฌ", "ะญ",
1232            "ะฎ", "ะฏ",
1233        },
1234        bg = { -- bulgarian
1235            "ะฐ", "ะฑ", "ะฒ", "ะณ", "ะด", "ะต", "ะถ", "ะท","ะธ", "ะน",
1236            "ะบ", "a", "ะป", "a", "ะผ", "ะฝ", "ะพ", "ะฟ", "ั€", "ั",
1237            "ั‚", "ัƒ", "ั„", "ั…", "ั†", "ั‡", "ัˆ", "ั‰", "ัŠ", "ัŒ",
1238            "ัŽ", "ั",
1239
1240            "ะ", "ะ‘", "ะ’", "ะ“", "ะ”", "ะ•", "ะ–", "ะ—","ะ˜", "ะ™",
1241            "ะš", "A", "ะ›", "A", "ะœ", "ะ", "ะž", "ะŸ", "ะ ", "ะก",
1242            "ะข", "ะฃ", "ะค", "ะฅ", "ะฆ", "ะง", "ะจ", "ะฉ", "ะช", "ะฌ",
1243            "ะฎ", "ะฏ",
1244        },
1245        pl = { -- polish
1246            "a", "ฤ…", "b", "c", "ฤ‡", "d", "e", "ฤ™", "f", "g",
1247            "h", "i", "j", "k", "l", "ล‚", "m", "n", "ล„", "o",
1248            "รณ", "p", "q", "r", "s", "ล›", "t", "u", "v", "w",
1249            "x", "y", "z", "ลบ", "ลผ",
1250
1251            "A", "ฤ„", "B", "C", "ฤ†", "D", "E", "ฤ˜", "F", "G",
1252            "H", "I", "J", "K", "L", "ล", "M", "N", "ลƒ", "O",
1253            "ร“", "P", "Q", "R", "S", "ลš", "T", "U", "V", "W",
1254            "X", "Y", "Z", "ลน", "ลป",
1255        },
1256        cz = { -- czech
1257            "a", "รก", "b", "c", "ฤ", "d", "ฤ", "e", "รฉ", "ฤ›",
1258            "f", "g", "h", "i", "รญ", "j", "k", "l", "m",
1259            "n", "ลˆ", "o", "รณ", "p", "q", "r", "ล™", "s", "ลก",
1260            "t", "ลฅ", "u", "รบ",  "ลฏ", "v", "w", "x",  "y", "รฝ",
1261            "z", "ลพ",
1262
1263            "A", "ร", "B", "C", "ฤŒ", "D", "ฤŽ", "E", "ร‰", "ฤš",
1264            "F", "G", "H", "I", "ร", "J", "K", "L", "M",
1265            "N", "ล‡", "O", "ร“", "P", "Q", "R", "ล˜", "S", "ล ",
1266            "T", "ลค", "U", "รš",  "ลฎ", "V", "W", "X",  "Y", "ร",
1267            "Z", "ลฝ",
1268        },
1269        sk = { -- slovak
1270            "a", "รก", "รค", "b", "c", "ฤ", "d", "ฤ",
1271            "e", "รฉ", "f", "g", "h", ch,  "i", "รญ", "j", "k",
1272            "l", "ฤบ", "ฤพ", "m", "n", "ลˆ", "o", "รณ", "รด", "p",
1273            "q", "r", "ล•", "s", "ลก", "t", "ลฅ", "u", "รบ", "v",
1274            "w", "x", "y", "รฝ", "z", "ลพ",
1275
1276            "A", "ร", "ร„", "B", "C", "ฤŒ", "D", "ฤŽ",
1277            "E", "ร‰", "F", "G", "H", "I", "ร", "J", "K",
1278            "L", "ฤน", "ฤฝ", "M", "N", "ล‡", "O", "ร“", "ร”", "P",
1279            "Q", "R", "ล”", "S", "ล ", "T", "ลค", "U", "รš", "V",
1280            "W", "X", "Y", "ร", "Z", "ลฝ",
1281        },
1282        hr = { -- croatian
1283            "a", "b", "c", "ฤ", "ฤ‡", "d", "ฤ‘", "e", "f",
1284            "g", "h", "i", "j", "k", "l", "m", "n",
1285            "o", "p", "r", "s", "ลก", "t", "u", "v", "z", "ลพ",
1286
1287            "A", "B", "C", "ฤŒ", "ฤ†", "D", "ฤ", "E", "F",
1288            "G", "H", "I", "J", "K", "L", "M", "N",
1289            "O", "P", "R", "S", "ล ", "T", "U", "V", "Z", "ลฝ",
1290        },
1291        sr = { -- serbian
1292            "ะฐ", "ะฑ", "ะฒ", "ะณ", "ะด", "ั’", "ะต", "ะถ", "ะท", "ะธ",
1293            "ั˜", "ะบ", "ะป", "ั™", "ะผ", "ะฝ", "ัš", "ะพ", "ะฟ", "ั€",
1294            "ั", "ั‚", "ั›", "ัƒ", "ั„", "ั…", "ั†", "ั‡", "ัŸ", "ัˆ",
1295
1296            "ะ", "ะ‘", "ะ’", "ะ“", "ะ”", "ะ‚", "ะ•", "ะ–", "ะ—", "ะ˜",
1297            "ะˆ", "ะš", "ะ›", "ะ‰", "ะœ", "ะ", "ะŠ", "ะž", "ะŸ", "ะ ",
1298            "ะก", "ะข", "ะ‹", "ะฃ", "ะค", "ะฅ", "ะฆ", "ะง", "ะ", "ะจ",
1299        },
1300        no = { -- norwegian
1301            "a", "b", "c", "d", "e", "f", "g", "h", "i", "j",
1302            "k", "l", "m", "n", "o", "p", "q", "r", "s", "t",
1303            "u", "v", "w", "x", "y", "z", "รฆ", "รธ", "รฅ",
1304
1305            "A", "B", "C", "D", "E", "F", "G", "H", "I", "J",
1306            "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T",
1307            "U", "V", "W", "X", "Y", "Z", "ร†", "ร˜", "ร…",
1308        },
1309        da = { --danish
1310            "a", "b", "c", "d", "e", "f", "g", "h", "i", "j",
1311            "k", "l", "m", "n", "o", "p", "q", "r", "s", "t",
1312            "u", "v", "w", "x", "y", "z", "รฆ", "รธ", "รฅ",
1313
1314            "A", "B", "C", "D", "E", "F", "G", "H", "I", "J",
1315            "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T",
1316            "U", "V", "W", "X", "Y", "Z", "ร†", "ร˜", "ร…",
1317        },
1318        sv = { -- swedish
1319            "a", "b", "c", "d", "e", "f", "g", "h", "i", "j",
1320            "k", "l", "m", "n", "o", "p", "q", "r", "s", "t",
1321            "u", "v", "w", "x", "y", "z", "รฅ", "รค", "รถ",
1322
1323            "A", "B", "C", "D", "E", "F", "G", "H", "I", "J",
1324            "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T",
1325            "U", "V", "W", "X", "Y", "Z", "ร…", "ร„", "ร–",
1326        },
1327        is = { -- islandic
1328            "a", "รก", "b", "d", "รฐ", "e", "รฉ", "f", "g", "h",
1329            "i", "รญ", "j", "k", "l", "m", "n", "o", "รณ", "p",
1330            "r", "s", "t", "u", "รบ", "v", "x", "y", "รฝ", "รพ",
1331            "รฆ", "รถ",
1332
1333            "A", "ร", "B", "D", "ร", "E", "ร‰", "F", "G", "H",
1334            "I", "ร", "J", "K", "L", "M", "N", "O", "ร“", "P",
1335            "R", "S", "T", "U", "รš", "V", "X", "Y", "ร", "รž",
1336            "ร†", "ร–",
1337        },
1338     -- gr = { -- greek
1339     --     "ฮฑ", "ฮฌ", "แฝฐ", "แพถ", "แพณ", "แผ€", "แผ", "แผ„", "แผ‚", "แผ†",
1340     --     "แผ", "แผ…", "แผƒ", "แผ‡", "แพ", "แพด", "แพฒ", "แพท", "แพ„", "แพ‚",
1341     --     "แพ…", "แพƒ", "แพ†", "แพ‡", "ฮฒ", "ฮณ", "ฮด", "ฮต", "ฮญ", "แฝฒ",
1342     --     "แผ", "แผ”", "แผ’", "แผ‘", "แผ•", "แผ“", "ฮถ", "ฮท", "ฮท", "ฮฎ",
1343     --     "แฝด", "แฟ†", "แฟƒ", "แผ ", "แผค", "แผข", "แผฆ", "แพ", "แผก", "แผฅ",
1344     --     "แผฃ", "แผง", "แพ‘", "แฟ„", "แฟ‚", "แฟ‡", "แพ”", "แพ’", "แพ•", "แพ“",
1345     --     "แพ–", "แพ—", "ฮธ", "ฮน", "ฮฏ", "แฝถ", "แฟ–", "แผฐ", "แผด", "แผฒ",
1346     --     "แผถ", "แผฑ", "แผต", "แผณ", "แผท", "ฯŠ", "ฮ", "แฟ’", "แฟ—", "ฮบ",
1347     --     "ฮป", "ฮผ", "ฮฝ", "ฮพ", "ฮฟ", "ฯŒ", "แฝธ", "แฝ€", "แฝ„", "แฝ‚",
1348     --     "แฝ", "แฝ…", "แฝƒ", "ฯ€", "ฯ", "แฟค", "แฟฅ", "ฯƒ", "ฯ‚", "ฯ„",
1349     --     "ฯ…", "ฯ", "แฝบ", "แฟฆ", "แฝ", "แฝ”", "แฝ’", "แฝ–", "แฝ‘", "แฝ•",
1350     --     "แฝ“", "แฝ—", "ฯ‹", "ฮฐ", "แฟข", "แฟง", "ฯ†", "ฯ‡", "ฯˆ", "ฯ‰",
1351     --     "ฯŽ", "แฝผ", "แฟถ", "แฟณ", "แฝ ", "แฝค", "แฝข", "แฝฆ", "แพ ", "แฝก",
1352     --     "แฝฅ", "แฝฃ", "แฝง", "แพก", "แฟด", "แฟฒ", "แฟท", "แพค", "แพข", "แพฅ",
1353     --     "แพฃ", "แพฆ", "แพง",
1354     --
1355     --     "ฮ‘", "ฮ†", "แพบ", "ฮ‘อ‚", "แผˆ", "แผ‰", "แผŒ", "แผŠ", "แผŽ",
1356     --     "แผ‰", "แผ", "แผ‹", "แผ",
1357     --     "ฮ’", "ฮ“", "ฮ”", "ฮ•", "ฮˆ", "แฟˆ",
1358     --     "แผ˜", "แผœ", "แผš", "แผ™", "แผ", "แผ›", "ฮ–", "ฮ—", "ฮ—", "ฮ‰",
1359     --     "แฟŠ", "ฮ—อ‚", "แผจ", "แผฌ", "แผช", "แผฎ", "แผฉ", "แผญ",
1360     --     "แผซ", "แผฏ",
1361     --     "ฮ˜", "ฮ™", "ฮŠ", "แฟš", "ฮ™อ‚", "แผธ", "แผผ", "แผบ",
1362     --     "แผพ", "แผน", "แผฝ", "แผป", "แผฟ", "ฮช", "ฮ™ฬˆฬ", "ฮ™ฬˆฬ€", "ฮ™ฬˆอ‚", "ฮš",
1363     --     "ฮ›", "ฮœ", "ฮ", "ฮž", "ฮŸ", "ฮŒ", "แฟธ", "แฝˆ", "แฝŒ", "แฝŠ",
1364     --     "แฝ‰", "แฝ", "แฝ‹", "ฮ ", "ฮก", "ฮกฬ“", "แฟฌ", "ฮฃ", "ฮฃ", "ฮค",
1365     --     "ฮฅ", "ฮŽ", "แฟช", "ฮฅอ‚", "ฮฅฬ“", "ฮฅฬ“ฬ", "ฮฅฬ“ฬ€", "ฮฅฬ“อ‚", "แฝ™", "แฝ",
1366     --     "แฝ›", "แฝŸ", "ฮซ", "ฮฅฬˆฬ", "ฮฅฬˆฬ€", "ฮฅฬˆอ‚", "ฮฆ", "ฮง", "ฮจ", "ฮฉ",
1367     --     "ฮ", "แฟบ", "ฮฉอ‚", "แฝจ", "แฝฌ", "แฝช", "แฝฎ", "แฝฉ",
1368     --     "แฝญ", "แฝซ", "แฝฏ",
1369     --     },
1370        gr = { -- greek
1371            "ฮฑ", "ฮฒ", "ฮณ", "ฮด", "ฮต", "ฮถ", "ฮท", "ฮธ", "ฮน", "ฮบ",
1372            "ฮป", "ฮผ", "ฮฝ", "ฮพ", "ฮฟ", "ฯ€", "ฯ", "ฯ‚", "ฯ„", "ฯ…",
1373            "ฯ†", "ฯ‡", "ฯˆ", "ฯ‰",
1374
1375            "ฮ‘", "ฮ’", "ฮ“", "ฮ”", "ฮ•", "ฮ–", "ฮ—", "ฮ˜", "ฮ™", "ฮš",
1376            "ฮ›", "ฮœ", "ฮ", "ฮž", "ฮŸ", "ฮ ", "ฮก", "ฮฃ", "ฮค", "ฮฅ",
1377            "ฮง", "ฮจ", "ฮฉ",
1378            },
1379        la = { -- latin
1380            "a", "ฤ", "ฤƒ", "b", "c", "d", "e", "ฤ“", "ฤ•", "f",
1381            "g", "h", "i", "ฤซ", "ฤญ", "j", "k", "l", "m", "n",
1382            "o", "ล", "ล", "p", "q", "r", "s", "t", "u", "ลซ",
1383            "ลญ", "v", "w", "x", "y", "ศณ", "yฬ†", "z", "รฆ",
1384
1385            "A", "ฤ€", "ฤ‚", "B", "C", "D", "E", "ฤ’", "ฤ”", "F",
1386            "G", "H", "I", "ฤช", "ฤฌ", "J", "K", "L", "M", "N",
1387            "O", "ลŒ", "ลŽ", "P", "Q", "R", "S", "T", "U", "ลช",
1388            "ลฌ", "V", "W", "X", "Y", "ศฒ", "Yฬ†", "Z", "ร†",
1389        },
1390        it = { -- italian
1391            "a", "รก", "b", "c", "d", "e", "รฉ", "รจ", "f", "g",
1392            "h", "i", "รญ", "รฌ", "j", "k", "l", "m", "n", "o",
1393            "รณ", "รฒ", "p", "q", "r", "s", "t", "u", "รบ", "รน",
1394            "v", "w", "x", "y", "z",
1395
1396            "A", "ร", "B", "C", "D", "E", "ร‰", "รˆ", "F", "G",
1397            "H", "I", "ร", "รŒ", "J", "K", "L", "M", "N", "O",
1398            "ร“", "ร’", "P", "Q", "R", "S", "T", "U", "รš", "ร™",
1399            "V", "W", "X", "Y", "Z",
1400        },
1401        ro = { -- romanian
1402            "a", "ฤƒ", "รข", "b", "c", "d", "e", "f", "g", "h",
1403            "i", "รฎ", "j", "k", "l", "m", "n", "o", "p", "q",
1404            "r", "s", "ศ™", "t", "ศ›", "u", "v", "w", "x", "y",
1405            "z",
1406
1407            "A", "ฤ‚", "ร‚", "B", "C", "D", "E", "F", "G", "H",
1408            "I", "รŽ", "J", "K", "L", "M", "N", "O", "P", "Q",
1409            "R", "S", "ศ˜", "T", "ศš", "U", "V", "W", "X", "Y",
1410            "Z",
1411        },
1412        es = { -- spanish
1413            "a", "รก", "b", "c", "d", "e", "รฉ", "f", "g", "h",
1414            "i", "รญ", "j", "k", "l", "m", "n", "รฑ", "o", "รณ",
1415            "p", "q", "r", "s", "t", "u", "รบ", "รผ", "v", "w",
1416            "x", "y", "z",
1417
1418            "A", "ร", "B", "C", "D", "E", "ร‰", "F", "G", "H",
1419            "I", "ร", "J", "K", "L", "M", "N", "ร‘", "O", "ร“",
1420            "P", "Q", "R", "S", "T", "U", "รš", "รœ", "V", "W",
1421            "X", "Y", "Z",
1422        },
1423        pt = { -- portuguese
1424            "a", "รก", "รข", "รฃ", "ร ", "b", "c", "รง", "d", "e",
1425            "รฉ", "รช", "f", "g", "h", "i", "รญ", "j", "k", "l",
1426            "m", "n", "o", "รณ", "รด", "รต", "p", "q", "r", "s",
1427            "t", "u", "รบ", "รผ", "v", "w", "x", "y", "z",
1428
1429            "A", "ร", "ร‚", "รƒ", "ร€", "B", "C", "ร‡", "D", "E",
1430            "ร‰", "รŠ", "F", "G", "H", "I", "ร", "J", "K", "L",
1431            "M", "N", "O", "ร“", "ร”", "ร•", "P", "Q", "R", "S",
1432            "T", "U", "รš", "รœ", "V", "W", "X", "Y", "Z",
1433        },
1434        lt = { -- lithuanian
1435            "a", "ฤ…", "b", "c", "ch",  "ฤ", "d", "e", "ฤ™", "ฤ—",
1436            "f", "g", "h", "i", "ฤฏ", "y", "j", "k", "l", "m",
1437            "n", "o", "p", "r", "s", "ลก", "t", "u", "ลณ", "ลซ",
1438            "v", "z", "ลพ",
1439
1440            "A", "ฤ„", "B", "C", "CH",  "ฤŒ", "D", "E", "ฤ˜", "ฤ–",
1441            "F", "G", "H", "I", "ฤฎ", "Y", "J", "K", "L", "M",
1442            "N", "O", "P", "R", "S", "ล ", "T", "U", "ลฒ", "ลช",
1443            "V", "Z", "ลฝ",
1444        },
1445        lv = { -- latvian
1446            "a", "ฤ", "b", "c", "ฤ", "d", "e", "ฤ“", "f", "g",
1447            "ฤฃ", "h", "i", "ฤซ", "j", "k", "ฤท", "l", "ฤผ", "m",
1448            "n", "ล†", "o", "ล", "p", "r", "ล—", "s", "ลก", "t",
1449            "u", "ลซ", "v", "z", "ลพ",
1450
1451            "A", "ฤ€", "B", "C", "ฤŒ", "D", "E", "ฤ’", "F", "G",
1452            "ฤข", "H", "I", "ฤช", "J", "K", "ฤถ", "L", "ฤป", "M",
1453            "N", "ล…", "O", "ลŒ", "P", "R", "ล–", "S", "ล ", "T",
1454            "U", "ลช", "V", "Z", "ลฝ",
1455        },
1456        hu = { -- hungarian
1457            "a", "รก", "b", "c", "d", "e", "รฉ",
1458            "f", "g", "h", "i", "รญ", "j", "k", "l",
1459            "m", "n", "o", "รณ", "รถ", "ล‘", "p", "q", "r",
1460            "s",  "t", "u", "รบ", "รผ", "ลฑ", "v", "w",
1461            "x", "y", "z",
1462
1463            "A", "ร", "B", "C", "D", "E", "ร‰",
1464            "F", "G", "H", "I", "ร", "J", "K", "L",
1465            "M", "N", "O", "ร“", "ร–", "ล", "P", "Q", "R",
1466            "S",  "T", "U", "รš", "รœ", "ลฐ", "V", "W",
1467            "X", "Y", "Z",
1468        },
1469        et = { -- estonian
1470            "a", "b", "d", "e", "f", "g", "h", "i", "j", "k",
1471            "l", "m", "n", "o", "p", "r", "s", "ลก", "z", "ลพ",
1472            "t", "u", "v", "w", "รต", "รค", "รถ", "รผ", "x", "y",
1473
1474            "A", "B", "D", "E", "F", "G", "H", "I", "J", "K",
1475            "L", "M", "N", "O", "P", "R", "S", "ล ", "Z", "ลฝ",
1476            "T", "U", "V", "W", "ร•", "ร„", "ร–", "รœ", "X", "Y",
1477        },
1478     -- jp = { -- japanese
1479     --     "ใ‚", "ใ„", "ใ†", "ใˆ", "ใŠ", "ใ‹", "ใ", "ใ", "ใ‘", "ใ“",
1480     --     "ใ•", "ใ—", "ใ™", "ใ›", "ใ", "ใŸ", "ใก", "ใค", "ใฆ", "ใจ",
1481     --     "ใช", "ใซ", "ใฌ", "ใญ", "ใฎ", "ใฏ", "ใฒ", "ใต", "ใธ", "ใป",
1482     --     "ใพ", "ใฟ", "ใ‚€", "ใ‚", "ใ‚‚", "ใ‚„", "ใ‚†", "ใ‚ˆ",
1483     --     "ใ‚‰", "ใ‚Š", "ใ‚‹", "ใ‚Œ", "ใ‚", "ใ‚", "ใ‚", "ใ‚‘", "ใ‚’", "ใ‚“",
1484     -- },
1485    }
1486
1487    local textselector = { }
1488    for k, v in next, textlists do
1489        textselector[#textselector+1] = k
1490    end
1491    table.sort(textselector)
1492
1493    -- We can populate these with the utf converter but it looks nicer here to
1494    -- see what we actually get. And it also tests how SciTE displays these
1495    -- special characters.
1496
1497    local mathsets = {
1498        { "tf", {
1499            "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
1500            "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
1501            "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"
1502        }, },
1503        { "bf", {
1504            "๐›", "๐œ", "๐", "๐ž", "๐Ÿ", "๐ ", "๐ก", "๐ข", "๐ฃ", "๐ค", "๐ฅ", "๐ฆ", "๐ง", "๐จ", "๐ฉ", "๐ช", "๐ซ", "๐ฌ", "๐ญ", "๐ฎ", "๐ฏ", "๐ฐ", "๐ฑ", "๐ฒ", "๐ณ",
1505            "๐€", "๐", "๐‚", "๐ƒ", "๐„", "๐…", "๐†", "๐‡", "๐ˆ", "๐‰", "๐Š", "๐‹", "๐Œ", "๐", "๐Ž", "๐", "๐", "๐‘", "๐’", "๐“", "๐”", "๐•", "๐–", "๐—", "๐˜", "๐™", "๐š",
1506            "๐ŸŽ", "๐Ÿ", "๐Ÿ", "๐Ÿ‘", "๐Ÿ’", "๐Ÿ“", "๐Ÿ”", "๐Ÿ•", "๐Ÿ–", "๐Ÿ—"
1507        }, },
1508        { "it",           {
1509            "๐‘Ž", "๐‘", "๐‘", "๐‘‘", "๐‘’", "๐‘“", "๐‘”", "โ„Ž", "๐‘–", "๐‘—", "๐‘˜", "๐‘™", "๐‘š", "๐‘›", "๐‘œ", "๐‘", "๐‘ž", "๐‘Ÿ", "๐‘ ", "๐‘ก", "๐‘ข", "๐‘ฃ", "๐‘ค", "๐‘ฅ", "๐‘ฆ", "๐‘ง",
1510            "๐ด", "๐ต", "๐ถ", "๐ท", "๐ธ", "๐น", "๐บ", "๐ป", "๐ผ", "๐ฝ", "๐พ", "๐ฟ", "๐‘€", "๐‘", "๐‘‚", "๐‘ƒ", "๐‘„", "๐‘…", "๐‘†", "๐‘‡", "๐‘ˆ", "๐‘‰", "๐‘Š", "๐‘‹", "๐‘Œ", "๐‘",
1511        }, },
1512        { "bi",           {
1513            "๐’‚", "๐’ƒ", "๐’„", "๐’…", "๐’†", "๐’‡", "๐’ˆ", "๐’‰", "๐’Š", "๐’‹", "๐’Œ", "๐’", "๐’Ž", "๐’", "๐’", "๐’‘", "๐’’", "๐’“", "๐’”", "๐’•", "๐’–", "๐’—", "๐’˜", "๐’™", "๐’š", "๐’›",
1514            "๐‘จ", "๐‘ฉ", "๐‘ช", "๐‘ซ", "๐‘ฌ", "๐‘ญ", "๐‘ฎ", "๐‘ฏ", "๐‘ฐ", "๐‘ฑ", "๐‘ฒ", "๐‘ณ", "๐‘ด", "๐‘ต", "๐‘ถ", "๐‘ท", "๐‘ธ", "๐‘น", "๐‘บ", "๐‘ป", "๐‘ผ", "๐‘ฝ", "๐‘พ", "๐‘ฟ", "๐’€", "๐’",
1515        }, },
1516        { "sc",       {
1517            "๐’ต", "๐’ถ", "๐’ท", "๐’ธ", "๐’น", "โ„ฏ", "๐’ป", "โ„Š", "๐’ฝ", "๐’พ", "๐’ฟ", "๐“€", "๐“", "๐“‚", "๐“ƒ", "โ„ด", "๐“…", "๐“†", "๐“‡", "๐“ˆ", "๐“‰", "๐“Š", "๐“‹", "๐“Œ", "๐“", "๐“Ž", "๐“",
1518            "๐’œ", "โ„ฌ", "๐’ž", "๐’Ÿ", "โ„ฐ", "โ„ฑ", "๐’ข", "โ„‹", "โ„", "๐’ฅ", "๐’ฆ", "โ„’", "โ„ณ", "๐’ฉ", "๐’ช", "๐’ซ", "๐’ฌ", "โ„›", "๐’ฎ", "๐’ฏ", "๐’ฐ", "๐’ฑ", "๐’ฒ", "๐’ณ", "๐’ด",
1519        }, },
1520        { "sc bf",   {
1521            "๐“ช", "๐“ซ", "๐“ฌ", "๐“ญ", "๐“ฎ", "๐“ฏ", "๐“ฐ", "๐“ฑ", "๐“ฒ", "๐“ณ", "๐“ด", "๐“ต", "๐“ถ", "๐“ท", "๐“ธ", "๐“น", "๐“บ", "๐“ป", "๐“ผ", "๐“ฝ", "๐“พ", "๐“ฟ", "๐”€", "๐”", "๐”‚", "๐”ƒ",
1522            "๐“", "๐“‘", "๐“’", "๐““", "๐“”", "๐“•", "๐“–", "๐“—", "๐“˜", "๐“™", "๐“š", "๐“›", "๐“œ", "๐“", "๐“ž", "๐“Ÿ", "๐“ ", "๐“ก", "๐“ข", "๐“ฃ", "๐“ค", "๐“ฅ", "๐“ฆ", "๐“ง", "๐“จ", "๐“ฉ",
1523        }, },
1524        { "fr",      {
1525            "๐”ž", "๐”Ÿ", "๐” ", "๐”ก", "๐”ข", "๐”ฃ", "๐”ค", "๐”ฅ", "๐”ฆ", "๐”ง", "๐”จ", "๐”ฉ", "๐”ช", "๐”ซ", "๐”ฌ", "๐”ญ", "๐”ฎ", "๐”ฏ", "๐”ฐ", "๐”ฑ", "๐”ฒ", "๐”ณ", "๐”ด", "๐”ต", "๐”ถ", "๐”ท",
1526            "๐”„", "๐”…", "โ„ญ", "๐”‡", "๐”ˆ", "๐”‰", "๐”Š", "โ„Œ", "โ„‘", "๐”", "๐”Ž", "๐”", "๐”", "๐”‘", "๐”’", "๐”“", "๐””", "โ„œ", "๐”–", "๐”—", "๐”˜", "๐”™", "๐”š", "๐”›", "๐”œ", "โ„จ",
1527        }, },
1528        { "ds", {
1529            "๐•“", "๐•”", "๐••", "๐•–", "๐•—", "๐•˜", "๐•™", "๐•š", "๐•›", "๐•œ", "๐•", "๐•ž", "๐•Ÿ", "๐• ", "๐•ก", "๐•ข", "๐•ฃ", "๐•ค", "๐•ฅ", "๐•ฆ", "๐•ง", "๐•จ", "๐•ฉ", "๐•ช", "๐•ซ",
1530            "๐”ธ", "๐”น", "โ„‚", "๐”ป", "๐”ผ", "๐”ฝ", "๐”พ", "โ„", "๐•€", "๐•", "๐•‚", "๐•ƒ", "๐•„", "โ„•", "๐•†", "โ„™", "โ„š", "โ„", "๐•Š", "๐•‹", "๐•Œ", "๐•", "๐•Ž", "๐•", "๐•", "โ„ค", "๐•’",
1531            "๐Ÿ˜", "๐Ÿ™", "๐Ÿš", "๐Ÿ›", "๐Ÿœ", "๐Ÿ", "๐Ÿž", "๐ŸŸ", "๐Ÿ ", "๐Ÿก"
1532        }, },
1533        { "fr bf",  {
1534            "๐•ฌ", "๐•ญ", "๐•ฎ", "๐•ฏ", "๐•ฐ", "๐•ฑ", "๐•ฒ", "๐•ณ", "๐•ด", "๐•ต", "๐•ถ", "๐•ท", "๐•ธ", "๐•น", "๐•บ", "๐•ป", "๐•ผ", "๐•ฝ", "๐•พ", "๐•ฟ", "๐–€", "๐–", "๐–‚", "๐–ƒ",
1535            "๐–„", "๐–…", "๐–†", "๐–‡", "๐–ˆ", "๐–‰", "๐–Š", "๐–‹", "๐–Œ", "๐–", "๐–Ž", "๐–", "๐–", "๐–‘", "๐–’", "๐–“", "๐–”", "๐–•", "๐––", "๐–—", "๐–˜", "๐–™", "๐–š", "๐–›", "๐–œ", "๐–", "๐–ž", "๐–Ÿ"
1536        }, },
1537        { "ss tf",        {
1538            "๐–บ", "๐–ป", "๐–ผ", "๐–ฝ", "๐–พ", "๐–ฟ", "๐—€", "๐—", "๐—‚", "๐—ƒ", "๐—„", "๐—…", "๐—†", "๐—‡", "๐—ˆ", "๐—‰", "๐—Š", "๐—‹", "๐—Œ", "๐—", "๐—Ž", "๐—", "๐—", "๐—‘", "๐—’", "๐—“",
1539            "๐– ", "๐–ก", "๐–ข", "๐–ฃ", "๐–ค", "๐–ฅ", "๐–ฆ", "๐–ง", "๐–จ", "๐–ฉ", "๐–ช", "๐–ซ", "๐–ฌ", "๐–ญ", "๐–ฎ", "๐–ฏ", "๐–ฐ", "๐–ฑ", "๐–ฒ", "๐–ณ", "๐–ด", "๐–ต", "๐–ถ", "๐–ท", "๐–ธ", "๐–น",
1540            "๐Ÿข", "๐Ÿฃ", "๐Ÿค", "๐Ÿฅ", "๐Ÿฆ", "๐Ÿง", "๐Ÿจ", "๐Ÿฉ", "๐Ÿช", "๐Ÿซ"
1541        }, },
1542        { "ss bf",        {
1543            "๐—ฎ", "๐—ฏ", "๐—ฐ", "๐—ฑ", "๐—ฒ", "๐—ณ", "๐—ด", "๐—ต", "๐—ถ", "๐—ท", "๐—ธ", "๐—น", "๐—บ", "๐—ป", "๐—ผ", "๐—ฝ", "๐—พ", "๐—ฟ", "๐˜€", "๐˜", "๐˜‚", "๐˜ƒ", "๐˜„", "๐˜…", "๐˜†", "๐˜‡",
1544            "๐—”", "๐—•", "๐—–", "๐——", "๐—˜", "๐—™", "๐—š", "๐—›", "๐—œ", "๐—", "๐—ž", "๐—Ÿ", "๐— ", "๐—ก", "๐—ข", "๐—ฃ", "๐—ค", "๐—ฅ", "๐—ฆ", "๐—ง", "๐—จ", "๐—ฉ", "๐—ช", "๐—ซ", "๐—ฌ", "๐—ญ",
1545            "๐Ÿฌ", "๐Ÿญ", "๐Ÿฎ", "๐Ÿฏ", "๐Ÿฐ", "๐Ÿฑ", "๐Ÿฒ", "๐Ÿณ", "๐Ÿด", "๐Ÿต",
1546        }, },
1547        { "ss it",        {
1548            "๐˜ข", "๐˜ฃ", "๐˜ค", "๐˜ฅ", "๐˜ฆ", "๐˜ง", "๐˜จ", "๐˜ฉ", "๐˜ช", "๐˜ซ", "๐˜ฌ", "๐˜ญ", "๐˜ฎ", "๐˜ฏ", "๐˜ฐ", "๐˜ฑ", "๐˜ฒ", "๐˜ณ", "๐˜ด", "๐˜ต", "๐˜ถ", "๐˜ท", "๐˜ธ", "๐˜น", "๐˜บ", "๐˜ป",
1549            "๐˜ˆ", "๐˜‰", "๐˜Š", "๐˜‹", "๐˜Œ", "๐˜", "๐˜Ž", "๐˜", "๐˜", "๐˜‘", "๐˜’", "๐˜“", "๐˜”", "๐˜•", "๐˜–", "๐˜—", "๐˜˜", "๐˜™", "๐˜š", "๐˜›", "๐˜œ", "๐˜", "๐˜ž", "๐˜Ÿ", "๐˜ ", "๐˜ก",
1550        }, },
1551        { "ss bi",        {
1552            "๐™–", "๐™—", "๐™˜", "๐™™", "๐™š", "๐™›", "๐™œ", "๐™", "๐™ž", "๐™Ÿ", "๐™ ", "๐™ก", "๐™ข", "๐™ฃ", "๐™ค", "๐™ฅ", "๐™ฆ", "๐™ง", "๐™จ", "๐™ฉ", "๐™ช", "๐™ซ", "๐™ฌ", "๐™ญ", "๐™ฎ", "๐™ฏ",
1553            "๐˜ผ", "๐˜ฝ", "๐˜พ", "๐˜ฟ", "๐™€", "๐™", "๐™‚", "๐™ƒ", "๐™„", "๐™…", "๐™†", "๐™‡", "๐™ˆ", "๐™‰", "๐™Š", "๐™‹", "๐™Œ", "๐™", "๐™Ž", "๐™", "๐™", "๐™‘", "๐™’", "๐™“", "๐™”", "๐™•",
1554        }, },
1555        { "tt",           {
1556            "๐šŠ", "๐š‹", "๐šŒ", "๐š", "๐šŽ", "๐š", "๐š", "๐š‘", "๐š’", "๐š“", "๐š”", "๐š•", "๐š–", "๐š—", "๐š˜", "๐š™", "๐šš", "๐š›", "๐šœ", "๐š", "๐šž", "๐šŸ", "๐š ", "๐šก", "๐šข", "๐šฃ",
1557            "๐™ฐ", "๐™ฑ", "๐™ฒ", "๐™ณ", "๐™ด", "๐™ต", "๐™ถ", "๐™ท", "๐™ธ", "๐™น", "๐™บ", "๐™ป", "๐™ผ", "๐™ฝ", "๐™พ", "๐™ฟ", "๐š€", "๐š", "๐š‚", "๐šƒ", "๐š„", "๐š…", "๐š†", "๐š‡", "๐šˆ", "๐š‰",
1558            "๐Ÿถ", "๐Ÿท", "๐Ÿธ", "๐Ÿน", "๐Ÿบ", "๐Ÿป", "๐Ÿผ", "๐Ÿฝ", "๐Ÿพ", "๐Ÿฟ"
1559        }, },
1560        { "gr tf",        {
1561            "ฮฑ", "ฮฒ", "ฮณ", "ฮด", "ฮต", "ฮถ", "ฮท", "ฮธ", "ฮน", "ฮบ", "ฮป", "ฮผ", "ฮฝ", "ฮพ", "ฮฟ", "ฯ€", "ฯ", "ฯ‚", "ฯƒ", "ฯ„", "ฯ…", "ฯ†", "ฯ‡", "ฯˆ", "ฯ‰",
1562            "ฮ‘", "ฮ’", "ฮ“", "ฮ”", "ฮ•", "ฮ–", "ฮ—", "ฮ˜", "ฮ™", "ฮš", "ฮ›", "ฮœ", "ฮ", "ฮž", "ฮŸ", "ฮ ", "ฮก", "ฮข", "ฮฃ", "ฮค", "ฮฅ", "ฮฆ", "ฮง", "ฮจ", "ฮฉ",
1563        }, },
1564        { "gr bf",        {
1565            "๐›‚", "๐›ƒ", "๐›„", "๐›…", "๐›†", "๐›‡", "๐›ˆ", "๐›‰", "๐›Š", "๐›‹", "๐›Œ", "๐›", "๐›Ž", "๐›", "๐›", "๐›‘", "๐›’", "๐›“", "๐›”", "๐›•", "๐›–", "๐›—", "๐›˜", "๐›™", "๐›š",
1566            "๐šจ", "๐šฉ", "๐šช", "๐šซ", "๐šฌ", "๐šญ", "๐šฎ", "๐šฏ", "๐šฐ", "๐šฑ", "๐šฒ", "๐šณ", "๐šด", "๐šต", "๐šถ", "๐šท", "๐šธ", "๐šน", "๐šบ", "๐šป", "๐šผ", "๐šฝ", "๐šพ", "๐šฟ", "๐›€",
1567        }, },
1568        { "gr it",        {
1569            "๐›ผ", "๐›ฝ", "๐›พ", "๐›ฟ", "๐œ€", "๐œ", "๐œ‚", "๐œƒ", "๐œ„", "๐œ…", "๐œ†", "๐œ‡", "๐œˆ", "๐œ‰", "๐œŠ", "๐œ‹", "๐œŒ", "๐œ", "๐œŽ", "๐œ", "๐œ", "๐œ‘", "๐œ’", "๐œ“", "๐œ”",
1570            "๐›ข", "๐›ฃ", "๐›ค", "๐›ฅ", "๐›ฆ", "๐›ง", "๐›จ", "๐›ฉ", "๐›ช", "๐›ซ", "๐›ฌ", "๐›ญ", "๐›ฎ", "๐›ฏ", "๐›ฐ", "๐›ฑ", "๐›ฒ", "๐›ณ", "๐›ด", "๐›ต", "๐›ถ", "๐›ท", "๐›ธ", "๐›น", "๐›บ",
1571        }, },
1572        { "gr bi",        {
1573            "๐œถ", "๐œท", "๐œธ", "๐œน", "๐œบ", "๐œป", "๐œผ", "๐œฝ", "๐œพ", "๐œฟ", "๐€", "๐", "๐‚", "๐ƒ", "๐„", "๐…", "๐†", "๐‡", "๐ˆ", "๐‰", "๐Š", "๐‹", "๐Œ", "๐", "๐Ž",
1574            "๐œœ", "๐œ", "๐œž", "๐œŸ", "๐œ ", "๐œก", "๐œข", "๐œฃ", "๐œค", "๐œฅ", "๐œฆ", "๐œง", "๐œจ", "๐œฉ", "๐œช", "๐œซ", "๐œฌ", "๐œญ", "๐œฎ", "๐œฏ", "๐œฐ", "๐œฑ", "๐œฒ", "๐œณ", "๐œด",
1575        }, },
1576        { "gr ss bf",     {
1577            "๐ฐ", "๐ฑ", "๐ฒ", "๐ณ", "๐ด", "๐ต", "๐ถ", "๐ท", "๐ธ", "๐น", "๐บ", "๐ป", "๐ผ", "๐ฝ", "๐พ", "๐ฟ", "๐ž€", "๐ž", "๐ž‚", "๐žƒ", "๐ž„", "๐ž…", "๐ž†", "๐ž‡", "๐žˆ",
1578            "๐–", "๐—", "๐˜", "๐™", "๐š", "๐›", "๐œ", "๐", "๐ž", "๐Ÿ", "๐ ", "๐ก", "๐ข", "๐ฃ", "๐ค", "๐ฅ", "๐ฆ", "๐ง", "๐จ", "๐ฉ", "๐ช", "๐ซ", "๐ฌ", "๐ญ", "๐ฎ",
1579        }, },
1580        { "gr ss bi",  {
1581            "๐žช", "๐žซ", "๐žฌ", "๐žญ", "๐žฎ", "๐žฏ", "๐žฐ", "๐žฑ", "๐žฒ", "๐žณ", "๐žด", "๐žต", "๐žถ", "๐žท", "๐žธ", "๐žน", "๐žบ", "๐žป", "๐žผ", "๐žฝ", "๐žพ", "๐žฟ", "๐Ÿ€", "๐Ÿ", "๐Ÿ‚",
1582            "๐ž", "๐ž‘", "๐ž’", "๐ž“", "๐ž”", "๐ž•", "๐ž–", "๐ž—", "๐ž˜", "๐ž™", "๐žš", "๐ž›", "๐žœ", "๐ž", "๐žž", "๐žŸ", "๐ž ", "๐žก", "๐žข", "๐žฃ", "๐žค", "๐žฅ", "๐žฆ", "๐žง", "๐žจ",
1583        }, },
1584        { "op", {
1585        }, },
1586        { "sy a", {
1587        }, },
1588        { "sy b", {
1589        }, },
1590        { "sy c", {
1591        }, },
1592    }
1593
1594    local mathlists    = { }
1595    local mathselector = { }
1596
1597    for i=1,#mathsets do
1598        local mathset = mathsets[i]
1599        mathselector[#mathselector+1] = mathset[1]
1600        mathlists[mathset[1]] = mathset[2]
1601    end
1602
1603    local enabled   = 0
1604    local usedlists = {
1605        { name = "text", current = "en", lists = textlists, selector = textselector },
1606        { name = "math", current = "tf", lists = mathlists, selector = mathselector },
1607    }
1608
1609    local function make_strip()
1610        local used     = usedlists[enabled]
1611        local lists    = used.lists
1612        local alphabet = lists[used.current]
1613        local selector = "(hide)(" .. concat(used.selector,")(") .. ")"
1614        local alphabet = "(" .. used.current .. ":)(" .. concat(alphabet,")(") .. ")"
1615        scite.StripShow(selector .. "\n" .. alphabet)
1616    end
1617
1618    local function hide_strip()
1619        scite.StripShow("")
1620    end
1621
1622    local function process_strip(control)
1623        local value = scite.StripValue(control)
1624        if value == "hide" then
1625            hide_strip()
1626            return
1627        elseif find(value,".+:") then
1628            return
1629        end
1630        local used = usedlists[enabled]
1631        if used.lists[value] then
1632            used.current = value
1633            make_strip()
1634        else
1635            editor:insert(editor.CurrentPos,value)
1636        end
1637    end
1638
1639    local function ignore_strip()
1640    end
1641
1642    function toggle_strip(name)
1643        enabled = enabled + 1
1644        if usedlists[enabled] then
1645            make_strip()
1646            OnStrip = process_strip
1647        else
1648            enabled = 0
1649            hide_strip()
1650            OnStrip = ignore_strip
1651        end
1652    end
1653
1654end
1655
1656-- Last time I checked the source the output pane errorlist lexer was still
1657-- hardcoded and could not be turned off ... alas.
1658
1659-- output.Lexer = 0
1660
1661-- SCI_SETBIDIRECTIONAL = SC_BIDIRECTIONAL_R2L
1662
1663-- Because SCITE messes around with package.loaded a regular require doesn't work, so
1664-- we overload it. We also add some paths.
1665
1666do
1667
1668    package.path = props.SciteDefaultHome .. "/context/lexers/?.lua;"        .. package.path
1669    package.path = props.SciteDefaultHome .. "/context/lexers/themes/?.lua;" .. package.path
1670    package.path = props.SciteDefaultHome .. "/context/lexers/data/?.lua;"   .. package.path
1671
1672    local required = require
1673    local loaded   = { }
1674
1675    require = function(name)
1676        local data = loaded[name]
1677        if not data then
1678            data = required(name)
1679            loaded[name] = data
1680        end
1681        return data
1682    end
1683
1684end
1685
1686-- It makes not much sense to trace back over whitespace and start lexing because in
1687-- our use case we can have nested lexers that themselve need a trace back. Also, in
1688-- large documents we seldom add at the end and therefore can as well parse the
1689-- whole document. Lua 5.4 is faster anyway.
1690--
1691-- The 'editor' object is not useable because (1) it is null terminating which is
1692-- bad for the PDF lexer. The 'styler' on the other hand is utf based and does not
1693-- work well for the byte based LPEG lexers. And, because 'OnStyle' creates a large
1694-- userdata blob anyway, we added a few methods to it.
1695--
1696-- Because this file will be reloaded after a change, and in the process messes with
1697-- some global properties (like package.loaded) we have some require hackery in the
1698-- lexer files.
1699
1700-- function OnStyle(styler)
1701--     local S_DEFAULT = 0
1702--     local S_IDENTIFIER = 1
1703--     local S_KEYWORD = 2
1704--     local S_UNICODECOMMENT = 3
1705--     local identifierCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
1706--     styler:StartStyling(styler.startPos, styler.lengthDoc, styler.initStyle)
1707--     while styler:More() do
1708--         if styler:State() == S_IDENTIFIER then
1709--             if not identifierCharacters:find(styler:Current(), 1, true) then
1710--                 local identifier = styler:Token()
1711--                 if identifier == "if" or identifier == "end" then
1712--                         styler:ChangeState(S_KEYWORD)
1713--                 end
1714--                 styler:SetState(S_DEFAULT)
1715--             end
1716--         elseif styler:State() == S_UNICODECOMMENT then
1717--             if styler:Match("ยป") then
1718--                 styler:ForwardSetState(S_DEFAULT)
1719--             end
1720--         end
1721--         if styler:State() == S_DEFAULT then
1722--             if styler:Match("ยซ") then
1723--                 styler:SetState(S_UNICODECOMMENT)
1724--             elseif identifierCharacters:find(styler:Current(), 1, true) then
1725--                 styler:SetState(S_IDENTIFIER)
1726--             end
1727--         end
1728--         styler:Forward()
1729--     end
1730--     styler:EndStyling()
1731-- end
1732
1733-- function OnStyle(styler)
1734--     local lineStart = editor:LineFromPosition(styler.startPos)
1735--     local lineEnd = editor:LineFromPosition(styler.startPos + styler.lengthDoc)
1736--     editor:StartStyling(styler.startPos, 31)
1737--     for line=lineStart,lineEnd,1 do
1738--         local lengthLine = editor:PositionFromLine(line+1) - editor:PositionFromLine(line)
1739--         local lineText = editor:GetLine(line)
1740--         local first = string.sub(lineText,1,1)
1741--         local style = 0
1742--         if first == "+" then
1743--                 style = 1
1744--         elseif first == " " or first == "\t" then
1745--                 style = 2
1746--         end
1747--         editor:SetStyling(lengthLine, style)
1748--     end
1749-- end
1750
1751do
1752
1753    local lexers     = nil
1754    local properties = props
1755    local partial    = false
1756    local partial    = true
1757    local trace      = false
1758--     local trace      = true
1759
1760    local loadedlexers = setmetatable ( { }, {
1761        __index = function(t,k)
1762                local language = match(k,"^script_(.*)$") or k
1763                if not lexers then
1764                    lexers = require("scite-context-lexer")
1765                    lexers.loadtheme(require("scite-context-theme"))
1766                end
1767                local name = "scite-context-lexer-" .. language
1768                local v = lexers.load(name)
1769                if v then
1770                    lexers.registertheme(properties,language)
1771                else
1772                    v = false
1773                end
1774                t[name]     = v
1775                t[k]        = v
1776                t[language] = v
1777                return v
1778            end
1779        } )
1780
1781    local function update(language,size,start,stop)
1782        if language then
1783            local syntax = loadedlexers[language]
1784            if syntax then
1785                lexers.scite_onstyle(syntax,editor,partial,language,props.FileNameExt,size,start,stop,trace)
1786            end
1787        end
1788    end
1789
1790    function Initialise()
1791        check_output_pane()
1792    end
1793
1794    function OnStyle(styler)
1795        -- for the moment here: editor.StyleClearAll(output) -- we have no way to nil the output lexer
1796        update(styler.language,editor.TextLength,styler.startPos,styler.lengthDoc)
1797    end
1798
1799    function OnOpen(filename)
1800        if trace then
1801            report("opening '%s' of %i bytes, language '%s'",filename,editor.TextLength,props.Language)
1802        end
1803        update(props.Language,editor.TextLength,0,editor.TextLength)
1804        check_output_pane()
1805    end
1806
1807    function OnSwitchFile(filename)
1808        if dirty[props.FileNameExt] then
1809            if trace then
1810                report("switching '%s' of %i bytes, language '%s'",filename,editor.TextLength,props.Language)
1811            end
1812            update(props.Language,editor.TextLength,0,editor.TextLength)
1813            dirty[props.FileNameExt] = false
1814        end
1815        check_output_pane()
1816    end
1817
1818    function OnChar()
1819        if not editor:AutoCActive() then
1820            local syntax = loadedlexers[props.Language]
1821            if syntax and syntax.completion then
1822                local stop   = editor.CurrentPos
1823                local start  = editor:WordStartPosition(stop,true)
1824                local length = stop - start
1825                if length >= 2 then
1826                    local snippet = editor:textrange(start,stop)
1827                    local list    = syntax.completion(snippet)
1828                    if list then
1829                        editor.AutoCMaxHeight = 30
1830                        editor.AutoCSeparator = 32
1831                        editor:AutoCShow(length,list)
1832                    end
1833                end
1834            end
1835        end
1836    end
1837
1838end
1839
1840-- function OnKey(a,b,c)
1841--     print("key",a,b,c)
1842-- end
1843
1844