scite-ctx.lua /size: 64 Kb    last modification: 2021-10-28 13:49
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
75local props = props or { }
76
77local byte, char = string.byte, string.char
78local lower, upper, format = string.lower, string.upper, string.format
79local gsub, sub, find, rep, match, gmatch = string.gsub, string.sub, string.find, string.rep, string.match, string.gmatch
80local sort, concat = table.sort, table.concat
81local loadstring = loadstring or load
82
83local function check_output_pane()
84    editor.StyleClearAll(output)
85end
86
87-- helpers : utf
88
89local magicstring = rep("<ctx-crlf/>", 2)
90
91local l2 = char(0xC0)
92local l3 = char(0xE0)
93local l4 = char(0xF0)
94
95local function utflen(str)
96    local n = 0
97    local l = 0
98    for s in gmatch(str,".") do
99        if l > 0 then
100            l = l - 1
101        else
102            n = n + 1
103            if s >= l4 then
104                l = 3
105            elseif s >= l3 then
106                l = 2
107            elseif s >= l2 then
108                l = 1
109            end
110        end
111    end
112    return n
113end
114
115local function utfchar(u)
116    if u <= 0x7F then
117        return char(
118            u
119        )
120    elseif u <= 0x7FF then
121        return char (
122            0xC0 | (u >> 6),
123            0x80 | (u & 0x3F)
124        )
125    elseif u <= 0xFFFF then
126        return char (
127            0xE0 | (u >> 12),
128            0x80 | ((u >> 6) & 0x3F),
129            0x80 | (u & 0x3F)
130        )
131    elseif n < 0x110000 then
132        local n = u - 0x10000
133        local r = ((n & 0xF0000) >> 16) + 1
134        return char (
135            0xF0 | (r >> 2),
136            0x80 | ((r & 3) << 4) | ((n & 0x0F000) >> 12),
137            0x80 | ((n & 0x00FC0) >> 6),
138            0x80 | (n & 0x0003F)
139        )
140    else
141        return utfchar(0xFFFD)
142    end
143end
144
145-- helpers: system
146
147function io.exists(filename)
148    local ok, result, message = pcall(io.open,filename)
149    if result then
150        io.close(result)
151        return true
152    else
153        return false
154    end
155end
156
157local function resultof(command)
158    local handle = io.popen(command,"r") -- already has flush
159    if handle then
160        local result = handle:read("*all") or ""
161        handle:close()
162        return result
163    else
164        return ""
165    end
166end
167
168function os.envvar(str)
169    local s = os.getenv(str)
170    if s ~= '' then
171        return s
172    end
173    s = os.getenv(upper(str))
174    if s ~= '' then
175        return s
176    end
177    s = os.getenv(lower(str))
178    if s ~= '' then
179        return s
180    end
181end
182
183local function loadtable(name)
184    local f = io.open(name,"rb")
185    if f then
186        f:close()
187        return dofile(name)
188    end
189end
190
191-- helpers: reporting
192
193local crlf   = "\n"
194local report = nil
195local trace  = trace
196
197if trace then
198    report = function(fmt,...)
199        if fmt then
200            trace(format(fmt,...))
201        end
202        trace(crlf)
203        io.flush()
204    end
205else
206    trace  = print
207    report = function(fmt,...)
208        if fmt then
209            trace(format(fmt,...))
210        else
211            trace("")
212        end
213        io.flush()
214    end
215end
216
217-- helpers: whatever (old code, we should use our libs)
218
219local function grab(str,delimiter)
220    local list = { }
221    for snippet in gmatch(str,delimiter) do
222        list[#list+1] = snippet
223    end
224    return list
225end
226
227local function expand(str)
228    return (gsub(str,"ENV%((%w+)%)", os.envvar))
229end
230
231local function strip(str)
232    return (gsub(str,"^%s*(.-)%s*$", "%1"))
233end
234
235local function alphasort(list,i)
236    if i and i > 0 then
237        local function alphacmp(a,b)
238            return lower(gsub(sub(a,i),'0',' ')) < lower(gsub(sub(b,i),'0',' '))
239        end
240        sort(list,alphacmp)
241    else
242        local function alphacmp(a,b)
243            return lower(a) < lower(b)
244        end
245        sort(list,alphacmp)
246    end
247end
248
249-- helpers: editor
250
251-- local function column_of_position(position)
252--     local line = editor:LineFromPosition(position)
253--     local oldposition = editor.CurrentPos
254--     local column = 0
255--     editor:GotoPos(position)
256--     while editor.CurrentPos ~= 0 and line == editor:LineFromPosition(editor.CurrentPos) do
257--         editor:CharLeft()
258--         column = column + 1
259--     end
260--     editor:GotoPos(oldposition)
261--     if line > 0 then
262--         return column -1
263--     else
264--         return column
265--     end
266-- end
267
268-- local function line_of_position(position)
269--     return editor:LineFromPosition(position)
270-- end
271
272local function extend_to_start()
273    local selectionstart = editor.SelectionStart
274    local selectionend = editor.SelectionEnd
275    local line = editor:LineFromPosition(selectionstart)
276    if line > 0 then
277        while line == editor:LineFromPosition(selectionstart-1) do
278            selectionstart = selectionstart - 1
279            editor:SetSel(selectionstart,selectionend)
280        end
281    else
282        selectionstart = 0
283    end
284    editor:SetSel(selectionstart,selectionend)
285    return selectionstart
286end
287
288local function extend_to_end() -- editor:LineEndExtend() does not work
289    local selectionstart = editor.SelectionStart
290    local selectionend = editor.SelectionEnd
291    local line = editor:LineFromPosition(selectionend)
292    while line == editor:LineFromPosition(selectionend+1) do
293        selectionend = selectionend + 1
294        editor:SetSel(selectionstart,selectionend)
295        if selectionend ~= editor.SelectionEnd then
296            break -- no progress
297        end
298    end
299    editor:SetSel(selectionstart,selectionend)
300    return selectionend
301end
302
303local function getfiletype()
304    local language = gsub(props.Language or "","script_","")
305    if language ~= "" then
306        return language
307    else
308        local firstline = editor:GetLine(0) or ""
309        if find(firstline,"^%%") then
310            return 'tex'
311        elseif find(firstline,"^<%?xml") then
312            return 'xml'
313        else
314            return 'unknown'
315        end
316    end
317end
318
319-- inspired by LuaExt's scite_Files
320
321-- local function get_dir_list(mask)
322--     local f
323--     if props['PLAT_GTK'] and props['PLAT_GTK'] ~= "" then
324--         f = io.popen('ls -1 ' .. mask)
325--     else
326--         mask = gsub(mask,'/','\\')
327--         local tmpfile = 'scite-ctx.tmp'
328--         local cmd = 'dir /b "' .. mask .. '" > ' .. tmpfile
329--         os.execute(cmd)
330--         f = io.open(tmpfile)
331--     end
332--     local files = { }
333--     if not f then -- path check added
334--         return files
335--     end
336--     for line in f:lines() do
337--         files[#files+1] = line
338--     end
339--     f:close()
340--     return files
341-- end
342
343--helpers : utf from editor
344
345local cat -- has to be set to editor.CharAt
346
347local function toutfcode(pos) -- if needed we can cache
348    local c1 = cat[pos]
349    if c1 < 0 then
350        c1 = 256 + c1
351    end
352    if c1 < 128 then
353        return c1, 1
354    end
355    if c1 < 224 then
356        local c2 = cat[pos+1]
357        if c2 < 0 then
358            c2 = 256 + c2
359        end
360        return c1 * 64 + c2 - 12416, 2
361    end
362    if c1 < 240 then
363        local c2 = cat[pos+1]
364        local c3 = cat[pos+2]
365        if c2 < 0 then
366            c2 = 256 + c2
367        end
368        if c3 < 0 then
369            c3 = 256 + c3
370        end
371        return (c1 * 64 + c2) * 64 + c3 - 925824, 3
372    end
373    if c1 < 245 then
374        local c2 = cat[pos+1]
375        local c3 = cat[pos+2]
376        local c4 = cat[pos+3]
377        if c2 < 0 then
378            c2 = 256 + c2
379        end
380        if c3 < 0 then
381            c3 = 256 + c3
382        end
383        if c4 < 0 then
384            c4 = 256 + c4
385        end
386        return ((c1 * 64 + c2) * 64 + c3) * 64 + c4 - 63447168, 4
387    end
388end
389
390-- banner
391
392do
393
394    check_output_pane()
395
396    print("Some CTX extensions:")
397
398    local wraplength = props['ctx.wraptext.length']
399
400    if wraplength and wraplength ~= "" then
401        print("\n-  ctx.wraptext.length is set to " .. wraplength)
402    else
403        print("\n-  ctx.wraptext.length is not set")
404    end
405
406    local helpinfo = props['ctx.helpinfo']
407
408    if helpinfo and helpinfo ~= "" then
409        print("\n-  key bindings:\n")
410        print((gsub(strip(helpinfo),"%s*|%s*","\n")))
411    else
412        print("\n-  no extra key bindings")
413    end
414
415    print("\n-  recognized first lines:\n")
416    print("xml   <?xml version='1.0' language='..'")
417    print("tex   % language=..")
418    print(" ")
419    print("(lexing is currently being upgraded / improved / made more native to scite)")
420    print(" ")
421
422end
423
424-- text functions
425
426-- written while listening to Talk Talk
427
428function wrap_text()
429
430    -- We always go to the end of a line, so in fact some of
431    -- the variables set next are not needed.
432
433    local length = props["ctx.wraptext.length"]
434
435    if length == '' then length = 80 else length = tonumber(length) end
436
437    local startposition = editor.SelectionStart
438    local endposition   = editor.SelectionEnd
439
440    if startposition == endposition then return end
441
442    editor:LineEndExtend()
443
444    startposition = editor.SelectionStart
445    endposition   = editor.SelectionEnd
446
447    -- local startline   = line_of_position(startposition)
448    -- local endline     = line_of_position(endposition)
449    -- local startcolumn = column_of_position(startposition)
450    -- local endcolumn   = column_of_position(endposition)
451    --
452    -- editor:SetSel(startposition,endposition)
453
454    local startline   = props['SelectionStartLine']
455    local endline     = props['SelectionEndLine']
456    local startcolumn = props['SelectionStartColumn'] - 1
457    local endcolumn   = props['SelectionEndColumn'] - 1
458
459    local replacement = { }
460    local templine    = ''
461    local tempsize    = 0
462    local indentation = rep(' ',startcolumn)
463    local selection   = editor:GetSelText()
464
465    selection = gsub(selection,"[\n\r][\n\r]","\n")
466    selection = gsub(selection,"\n\n+",' ' .. magicstring .. ' ')
467    selection = gsub(selection,"^%s",'')
468
469    for snippet in gmatch(selection,"%S+") do
470        if snippet == magicstring then
471            replacement[#replacement+1] = templine
472            replacement[#replacement+1] = ""
473            templine = ''
474            tempsize = 0
475        else
476            local snipsize = utflen(snippet)
477            if tempsize + snipsize > length then
478                replacement[#replacement+1] = templine
479                templine = indentation .. snippet
480                tempsize = startcolumn + snipsize
481            elseif tempsize == 0 then
482                templine = indentation .. snippet
483                tempsize = tempsize + startcolumn + snipsize
484            else
485                templine = templine .. ' ' .. snippet
486                tempsize = tempsize + 1 + snipsize
487            end
488        end
489    end
490
491    replacement[#replacement+1] = templine
492    replacement[1] = gsub(replacement[1],"^%s+",'')
493
494    if endcolumn == 0 then
495        replacement[#replacement+1] = ""
496    end
497
498    editor:ReplaceSel(concat(replacement,"\n"))
499
500end
501
502function unwrap_text()
503
504    local startposition = editor.SelectionStart
505    local endposition   = editor.SelectionEnd
506
507    if startposition == endposition then return end
508
509    editor:HomeExtend()
510    editor:LineEndExtend()
511
512    startposition = editor.SelectionStart
513    endposition   = editor.SelectionEnd
514
515    local magicstring = rep("<multiplelines/>", 2)
516    local selection   = gsub(editor:GetSelText(),"[\n\r][\n\r]+", ' ' .. magicstring .. ' ')
517    local replacement = ''
518
519    for snippet in gmatch(selection,"%S+") do
520        if snippet == magicstring then
521            replacement = replacement .. "\n"
522        else
523            replacement = replacement .. snippet .. "\n"
524        end
525    end
526
527    if endcolumn == 0 then replacement = replacement .. "\n" end
528
529    editor:ReplaceSel(replacement)
530
531end
532
533function sort_text()
534
535    local startposition = editor.SelectionStart
536    local endposition   = editor.SelectionEnd
537
538    if startposition == endposition then return end
539
540    -- local startcolumn = column_of_position(startposition)
541    -- local endcolumn   = column_of_position(endposition)
542    --
543    -- editor:SetSel(startposition,endposition)
544
545    local startline   = props['SelectionStartLine']
546    local endline     = props['SelectionEndLine']
547    local startcolumn = props['SelectionStartColumn'] - 1
548    local endcolumn   = props['SelectionEndColumn']   - 1
549
550    startposition = extend_to_start()
551    endposition   = extend_to_end()
552
553    local selection = gsub(editor:GetSelText(), "%s*$", '')
554    local list = grab(selection,"[^\n\r]+")
555    alphasort(list, startcolumn)
556    local replacement = concat(list, "\n")
557
558    editor:GotoPos(startposition)
559    editor:SetSel(startposition,endposition)
560
561    if endcolumn == 0 then replacement = replacement .. "\n" end
562
563    editor:ReplaceSel(replacement)
564
565end
566
567do
568
569    local data = {
570        xml = {
571            pattern = "%<%!%-%-.-%-%-%>"
572        },
573        tex = {
574            pattern = "%%.-[\r\n]"
575        },
576    }
577
578    function remove_comment()
579        local filetype  = getfiletype()
580        local filedata  = data[filetype]
581        local selection = editor:GetSelText()
582        if filedata and selection ~= "" then
583            local startposition = editor.SelectionStart
584            local endposition   = editor.SelectionEnd
585            selection = gsub(selection,filedata.pattern,"")
586            selection = gsub(selection,"%s+","")
587            editor:ReplaceSel(selection)
588        end
589    end
590
591end
592
593do
594
595    -- I really needed we can do version numbers but no one uses them.
596
597    local patterns = {
598        "(%d+)%s+(%d+)%s+obj",
599        "(%d+)%s+(%d+)%s+R",
600    }
601
602    local function show_pdf_object(n)
603        local name = props.FilePath
604        local data = resultof("mtxrun --script pdf --object=" .. n .. " " .. name)
605        print(format("file: %s, object number: %s, object data:\n",name,n))
606        print(data)
607    end
608
609    function filter_pdf_object()
610        local filetype  = getfiletype()
611        local selection = editor:GetSelText()
612        if filetype == "pdf" and selection ~= 0 then
613            local n, m
614            for i=1,#patterns do
615                n, m = match(selection,patterns[i])
616                if n and m then
617                    break
618                end
619            end
620            n = tonumber(n)
621            m = tonumber(m)
622            if n and m then
623                show_pdf_object(n)
624            end
625        end
626    end
627
628    function search_pdf_object()
629        local filetype  = getfiletype()
630        local selection = editor:GetSelText()
631        if filetype == "pdf" and selection ~= 0 then
632            local onstrip = OnStrip
633            function OnStrip(control,change)
634                if control == 2 then
635                    local n = tonumber(scite.StripValue(1))
636                    if n then
637                        show_pdf_object(n)
638                    end
639                    OnStrip = onstrip
640                    scite.StripShow("")
641                end
642            end
643            scite.StripShow("!'Object Number:'{}(&Search)\n")
644        end
645    end
646
647end
648
649do
650
651    local valid = {
652        xml = true,
653        tex = true,
654    }
655
656    function document_text()
657        local filetype = getfiletype()
658        if valid[filetype or ""] then
659            local startposition = editor.SelectionStart
660            local endposition   = editor.SelectionEnd
661            if startposition ~= endposition then
662                startposition = extend_to_start()
663                endposition   = extend_to_end()
664                editor:SetSel(startposition,endposition)
665                local replacement = ''
666                for i = editor:LineFromPosition(startposition), editor:LineFromPosition(endposition) do
667                    local str = editor:GetLine(i)
668                    if filetype == 'xml' then
669                        if find(str,"^<%!%-%- .* %-%->%s*$") then
670                            replacement = replacement .. gsub(str,"^<%!%-%- (.*) %-%->(%s*)$","%1\n")
671                        elseif find(str,"%S") then
672                            replacement = replacement .. '<!-- ' .. gsub(str,"(%s*)$",'') .. " -->\n"
673                        else
674                            replacement = replacement .. str
675                        end
676                    else
677                        if find(str,"^%%D%s+$") then
678                            replacement = replacement .. "\n"
679                        elseif find(str,"^%%D ") then
680                            replacement = replacement .. gsub(str,"^%%D ",'')
681                        else
682                            replacement = replacement .. '%D ' .. str
683                        end
684                    end
685                end
686                replacement = gsub(replacement,"[\n\r]$",'')
687                editor:ReplaceSel(replacement)
688            end
689        end
690    end
691
692end
693
694do
695
696    local data = {
697        xml = {
698            quote = {
699                left  = "<quote>",
700                right = "</quote>",
701            },
702            quotation = {
703                left  = "<quotation>",
704                right = "</quotation>",
705            },
706        },
707        tex = {
708            quote = {
709                left  = "\\quote {",
710                right = "}",
711            },
712            quotation = {
713                left  = "\\quotation {",
714                right = "}",
715            },
716        },
717    }
718
719    function quote_text()
720        local filetype  = getfiletype()
721        local filedata  = data[filetype]
722        local selection = editor:GetSelText()
723        if filedata and selection ~= "" then
724            selection = gsub(selection,[["(.-)"]], filedata.quotation.left .. "%1" .. filedata.quotation.right)
725            selection = gsub(selection,[['(.-)']], filedata.quote    .left .. "%1" .. filedata.quote    .right)
726            editor:ReplaceSel(selection)
727        end
728    end
729
730    function quote_text_s()
731        local filetype  = getfiletype()
732        local filedata  = data[filetype]
733        local selection = editor:GetSelText()
734        if filedata and selection ~= "" then
735            selection = filedata.quote.left .. selection .. filedata.quote.right
736            editor:ReplaceSel(selection)
737        end
738    end
739
740    function quote_text_d()
741        local filetype  = getfiletype()
742        local filedata  = data[filetype]
743        local selection = editor:GetSelText()
744        if filedata and selection ~= "" then
745            selection = filedata.quotation.left .. selection .. filedata.quotation.right
746            editor:ReplaceSel(selection)
747        end
748    end
749
750end
751
752do
753
754    local data = {
755        xml = {
756            pattern     = [[(>[^<%-][^<%-]+)([-/])(%w%w+)]],
757            replacement = [[%1<compound token="%2"/>%3]],
758        },
759        tex = {
760            pattern     = [[([^|])([-/]+)([^|])]],
761            replacement = [[%1|%2|%3]],
762        },
763    }
764
765    function compound_text()
766
767        local filetype  = getfiletype()
768        local filedata  = data[filetype]
769        local selection = editor:GetSelText()
770        if filedata and selection ~= "" then
771            selection = gsub(selection,filedata.pattern,filedata.replacement)
772            editor:ReplaceSel(selection)
773        end
774
775    end
776
777end
778
779-- There used to be some spell checking code here usign regular Scite
780-- mechanisms but that has been moved to the lexer code already a while
781-- ago so I removed the (pre 2005) code here. (See archive.)
782
783do
784
785    function add_text()
786
787        local startposition = editor.SelectionStart
788        local endposition   = editor.SelectionEnd
789
790        if startposition == endposition then return end
791
792        local selection = gsub(editor:GetSelText(), "%s*$", '')
793
794        local n, sum = 0, 0
795        for s in gmatch(selection,"[%-%+]?[%d%.%,]+") do -- todo: proper lpeg
796            s = gsub(s,",",".")
797            local m = tonumber(s)
798            if m then
799                n = n + 1
800                sum = sum + m
801                report("%4i : %s",n,m)
802            end
803        end
804        if n > 0 then
805            report()
806            report("sum  : %s",sum)
807        else
808            report("no numbers selected")
809        end
810
811    end
812
813end
814
815local dirty = { } do
816
817    local bidi = nil
818
819    local mapping = {
820        l   = 0, -- "Left-to-Right",
821        lre = 7, -- "Left-to-Right Embedding",
822        lro = 7, -- "Left-to-Right Override",
823        r   = 2, -- "Right-to-Left",
824        al  = 3, -- "Right-to-Left Arabic",
825        rle = 7, -- "Right-to-Left Embedding",
826        rlo = 7, -- "Right-to-Left Override",
827        pdf = 7, -- "Pop Directional Format",
828        en  = 4, -- "European Number",
829        es  = 4, -- "European Number Separator",
830        et  = 4, -- "European Number Terminator",
831        an  = 5, -- "Arabic Number",
832        cs  = 6, -- "Common Number Separator",
833        nsm = 6, -- "Non-Spacing Mark",
834        bn  = 7, -- "Boundary Neutral",
835        b   = 0, -- "Paragraph Separator",
836        s   = 7, -- "Segment Separator",
837        ws  = 0, -- "Whitespace",
838        on  = 7, -- "Other Neutrals",
839    }
840
841    -- todo: take from scite-context-theme.lua
842
843    local colors = { -- b g r
844        [0] = 0x000000, -- black
845        [1] = 0x00007F, -- red
846        [2] = 0x007F00, -- green
847        [3] = 0x7F0000, -- blue
848        [4] = 0x7F7F00, -- cyan
849        [5] = 0x7F007F, -- magenta
850        [6] = 0x007F7F, -- yellow
851        [7] = 0x007FB0, -- orange
852        [8] = 0x4F4F4F, -- dark
853    }
854
855    -- in principle, when we could inject some funny symbol that is not part of the
856    -- stream and/or use a different extra styling for each snippet then selection
857    -- would work and rendering would look better too ... one problem is that a font
858    -- rendering can collapse characters due to font features
859
860    function show_bidi()
861
862        cat = editor.CharAt
863
864        editor.CodePage = SC_CP_UTF8
865
866        for i=1,#colors do -- 0,#colors
867           editor.StyleFore[i] = colors[i] -- crashes
868        end
869
870        if not bidi then
871            bidi = require("context.scite-ctx-bidi")
872        end
873
874        local len = editor.TextLength
875        local str = editor:textrange(0,len-1)
876
877        local t = { }
878        local a = { }
879        local n = 0
880        local i = 0
881
882        local v
883        while i < len do
884            n = n + 1
885            v, s = toutfcode(i)
886            t[n] = v
887            a[n] = s
888            i = i + s
889        end
890
891        local t = bidi.process(t)
892
893        editor:StartStyling(0,31)
894
895        local defaultcolor = mapping.l
896        local mirrorcolor  = 1
897
898        if false then
899            for i=1,n do
900                local direction = t[i].direction
901                local color     = direction and (mapping[direction] or 0) or defaultcolor
902                editor:SetStyling(a[i],color)
903            end
904        else
905            local lastcolor = -1
906            local runlength = 0
907            for i=1,n do
908                local ti = t[i]
909                local direction = ti.direction
910                local mirror    = t[i].mirror
911                local color     = (mirror and mirrorcolor) or (direction and mapping[direction]) or defaultcolor
912                if color == lastcolor then
913                    runlength = runlength + a[i]
914                else
915                    if runlength > 0 then
916                        editor:SetStyling(runlength,lastcolor)
917                    end
918                    lastcolor = color
919                    runlength = a[i]
920                end
921            end
922            if runlength > 0 then
923                editor:SetStyling(runlength,lastcolor)
924            end
925        end
926
927        editor:SetStyling(2,31)
928
929        dirty[props.FileNameExt] = true
930
931    end
932
933end
934
935-- menu
936
937local menuactions   = { }
938local menufunctions = { }
939local menuentries   = { }
940
941function UserListShow(menutrigger, menulist)
942    if type(menulist) == "string" then
943        menuentries = { }
944        menuactions = { }
945        for item in gmatch(menulist,"[^%|]+") do
946            if item ~= "" then
947                -- why not just a split
948                for key, value in gmatch(item,"%s*(.+)=(.+)%s*") do
949                    menuentries[#menuentries+1] = key
950                    menuactions[key] = value
951                end
952            end
953        end
954    else
955        menuentries = menulist
956        menuactions = false
957    end
958    local menustring = concat(menuentries,'|')
959    if menustring == "" then
960        report("there are no (further) options defined for this file type")
961    else
962        editor.AutoCSeparator = byte('|')
963        editor:UserListShow(menutrigger,menustring)
964        editor.AutoCSeparator = byte(' ')
965    end
966end
967
968function OnUserListSelection(trigger,choice)
969    if menufunctions[trigger] then
970        return menufunctions[trigger](menuactions and menuactions[choice] or choice)
971    else
972        return false
973    end
974end
975
976-- main menu
977
978do
979
980    local menutrigger = 12
981
982    function show_menu(menulist)
983        UserListShow(menutrigger, menulist)
984    end
985
986    function process_menu(action)
987        if not find(action,"%(%)$") then
988            assert(load(action .. "()"))()
989        else
990            assert(load(action))()
991        end
992    end
993
994    menufunctions[12] = process_menu
995
996end
997
998-- The template code is old but used so we cannot drop it. I will cook up a better
999-- system some day, using Lua tables instead.
1000
1001do
1002
1003    -- <?context-directive job ctxtemplate demotemplate.lua ?>
1004
1005    local templatetrigger = 13
1006
1007    local ctx_template_file = "scite-ctx-templates.lua"
1008    local ctx_template_list = { }
1009    local ctx_template_menu = { }
1010
1011 -- function ctx_list_loaded(path)
1012 --     return ctx_path_list[path] and #ctx_path_list[path] > 0
1013 -- end
1014
1015    local patterns = {
1016        xml = "<%?context%-directive job ctxtemplate (.-) %?>"
1017    }
1018
1019    local function loadtemplate(name)
1020        local temp = gsub(name,"\\","/")
1021        local okay = loadtable(temp)
1022        if okay then
1023            print("template loaded: " .. name)
1024        end
1025        return okay
1026    end
1027
1028    local function loadtemplatefrompaths(path,name)
1029        return loadtemplate(path ..       "/" .. name) or
1030               loadtemplate(path ..    "/../" .. name) or
1031               loadtemplate(path .. "/../../" .. name)
1032    end
1033
1034    function insert_template(templatelist)
1035        local path   = props["FileDir"]
1036        local suffix = props["FileExt"]
1037        local list   = ctx_template_list[path]
1038        if list == nil then
1039            local pattern = patterns[suffix]
1040            local okay    = false
1041            if pattern then
1042                for i=0,9 do
1043                    local line = editor:GetLine(i) or ""
1044                    local name = match(line,pattern)
1045                    if name then
1046                        okay = loadtemplatefrompaths(path,name)
1047                        if not okay then
1048                            name = resultof("mtxrun --find-file " .. name)
1049                            if name then
1050                                name = gsub(name,"\n","")
1051                                okay = loadtemplate(name)
1052                            end
1053                        end
1054                        break
1055                    end
1056                end
1057            end
1058            if not okay then
1059                okay = loadtemplatefrompaths(path,ctx_template_file)
1060            end
1061            if not okay then
1062                okay = loadtemplate(props["SciteDefaultHome"] .. "/context/" .. ctx_template_file)
1063            end
1064            if okay then
1065                list = okay
1066            else
1067                list = false
1068                print("no template file found")
1069            end
1070            ctx_template_list[path] = list
1071        end
1072        ctx_template_menu = { }
1073        if list then
1074            local okay = list[suffix]
1075            if okay then
1076                local menu = { }
1077                for i=1,#okay do
1078                    local o = okay[i]
1079                    local n = o.name
1080                    menu[#menu+1] = n
1081                    ctx_template_menu[n] = o
1082                end
1083                UserListShow(templatetrigger, menu, true)
1084            end
1085        end
1086    end
1087
1088    function inject_template(action)
1089        if ctx_template_menu then
1090            local a = ctx_template_menu[action]
1091            if a then
1092                local template = a.template
1093                local nature   = a.nature
1094                if template then
1095                    local margin = props['SelectionStartColumn'] - 1
1096                 -- template = gsub(template,"\\n","\n")
1097                    template = gsub(template,"%?%?","_____")
1098                    local pos = find(template,"%?")
1099                    template = gsub(template,"%?","")
1100                    template = gsub(template,"_____","?")
1101                    if nature == "display" then
1102                        local spaces = rep(" ",margin)
1103                        if not find(template,"\n$") then
1104                            template = template .. "\n"
1105                        end
1106                        template = gsub(template,"\n",function(s)
1107                            return "\n" .. spaces
1108                        end)
1109                        pos = pos + margin -- todo: check for first line
1110                    end
1111                    editor:insert(editor.CurrentPos,template)
1112                    if pos then
1113                        editor.CurrentPos = editor.CurrentPos + pos - 1
1114                        editor.SelectionStart = editor.CurrentPos
1115                        editor.SelectionEnd = editor.CurrentPos
1116                        editor:GotoPos(editor.CurrentPos)
1117                    end
1118                end
1119            end
1120        end
1121    end
1122
1123    menufunctions[13] = inject_template
1124
1125end
1126
1127do
1128
1129    -- These will become external and taken from sort-lan.lua in the
1130    -- ConTeXt distribution.
1131
1132    local textlists = {
1133        en = {
1134            "a", "b", "c", "d", "e", "f", "g", "h", "i", "j",
1135            "k", "l", "m", "n", "o", "p", "q", "r", "s", "t",
1136            "u", "v", "w", "x", "y", "z",
1137
1138            "A", "B", "C", "D", "E", "F", "G", "H", "I", "J",
1139            "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T",
1140            "U", "V", "W", "X", "Y", "Z",
1141        },
1142        nl = {
1143            "a", "b", "c", "d", "e", "f", "g", "h", "i", "j",
1144            "k", "l", "m", "n", "o", "p", "q", "r", "s", "t",
1145            "u", "v", "w", "x", "y", "z",
1146
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        fr = {
1152            "a", "æ", "b", "c", "ç", "d", "e", "è", "é", "ê",
1153            "f", "g", "h", "i", "j", "k", "l", "m", "n", "o",
1154            "p", "q", "r", "s", "t", "u", "v", "w", "x", "y",
1155            "z",
1156
1157            "A", "Æ", "B", "C", "Ç", "D", "E", "È", "É", "Ê",
1158            "F", "G", "H", "I", "J", "K", "L", "M", "N", "O",
1159            "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y",
1160            "Z",
1161
1162        },
1163        de = {
1164            "a", "ä", "b", "c", "d", "e", "f", "g", "h", "i",
1165            "j", "k", "l", "m", "n", "o", "ö", "p", "q", "r",
1166            "s", "ß", "t", "u", "ü", "v", "w", "x", "y", "z",
1167
1168            "A", "Ä", "B", "C", "D", "E", "F", "G", "H", "I",
1169            "J", "K", "L", "M", "N", "O", "Ö", "P", "Q", "R",
1170            "S", "SS", "T", "U", "Ü", "V", "W", "X", "Y", "Z",
1171        },
1172        fi = { -- finish
1173            "a", "b", "c", "d", "e", "f", "g", "h", "i", "j",
1174            "k", "l", "m", "n", "o", "p", "q", "r", "s", "t",
1175            "u", "v", "w", "x", "y", "z", "å", "ä", "ö",
1176
1177            "A", "B", "C", "D", "E", "F", "G", "H", "I", "J",
1178            "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T",
1179            "U", "V", "W", "X", "Y", "Z", "Å", "Ä", "Ö",
1180        },
1181        sl = { -- slovenian
1182            "a", "b", "c", "č", "ć", "d", "đ", "e", "f", "g", "h", "i",
1183            "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "š", "t",
1184            "u", "v", "w", "x", "y", "z", "ž",
1185
1186            "A", "B", "C", "Č", "Ć", "D", "Đ", "E", "F", "G", "H", "I",
1187            "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "Š", "T",
1188            "U", "V", "W", "X", "Y", "Z", "Ž",
1189        },
1190        ru = { -- rusian
1191            "а", "б", "в", "г", "д", "е", "ё", "ж", "з", "и",
1192            "і", "й", "к", "л", "м", "н", "о", "п", "р", "с",
1193            "т", "у", "ф", "х", "ц", "ч", "ш", "щ", "ъ", "ы",
1194            "ь", "ѣ", "э", "ю", "я", "ѳ", "ѵ",
1195
1196            "А", "Б", "В", "Г", "Д", "Е", "Ё", "Ж", "З", "И",
1197            "І", "Й", "К", "Л", "М", "Н", "О", "П", "Р", "С",
1198            "Т", "У", "Ф", "Х", "Ц", "Ч", "Ш", "Щ", "Ъ", "Ы",
1199            "Ь", "Ѣ", "Э", "Ю", "Я", "Ѳ", "Ѵ",
1200        },
1201        uk = { -- ukraninuan
1202            "а", "б", "в", "г", "ґ", "д", "е", "є", "ж", "з", "и", "і",
1203            "ї", "й", "к", "л", "м", "н", "о", "п", "р", "с", "т", "у",
1204            "ф", "х", "ц", "ч", "ш", "щ", "ь", "ю", "я",
1205
1206            "А", "Б", "В", "Г", "Ґ", "Д", "Е", "Є", "Ж", "З", "И", "І",
1207            "Ї", "Й", "К", "Л", "М", "Н", "О", "П", "Р", "С", "Т", "У",
1208            "Ф", "Х", "Ц", "Ч", "Ш", "Щ", "Ь", "Ю", "Я",
1209        },
1210        be = { -- belarusia
1211            "а", "б", "в", "г", "д", "е", "ё", "ж", "з", "і",
1212            "й", "к", "л", "м", "н", "о", "п", "р", "с", "т",
1213            "у", "ў", "ф", "х", "ц", "ч", "ш", "ы", "ь", "э",
1214            "ю", "я",
1215
1216            "А", "Б", "В", "Г", "Д", "Е", "Ё", "Ж", "З", "І",
1217            "Й", "К", "Л", "М", "Н", "О", "П", "Р", "С", "Т",
1218            "У", "Ў", "Ф", "Х", "Ц", "Ч", "Ш", "Ы", "Ь", "Э",
1219            "Ю", "Я",
1220        },
1221        bg = { -- bulgarian
1222            "а", "б", "в", "г", "д", "е", "ж", "з","и", "й",
1223            "к", "a", "л", "a", "м", "н", "о", "п", "р", "с",
1224            "т", "у", "ф", "х", "ц", "ч", "ш", "щ", "ъ", "ь",
1225            "ю", "я",
1226
1227            "А", "Б", "В", "Г", "Д", "Е", "Ж", "З","И", "Й",
1228            "К", "A", "Л", "A", "М", "Н", "О", "П", "Р", "С",
1229            "Т", "У", "Ф", "Х", "Ц", "Ч", "Ш", "Щ", "Ъ", "Ь",
1230            "Ю", "Я",
1231        },
1232        pl = { -- polish
1233            "a", "ą", "b", "c", "ć", "d", "e", "ę", "f", "g",
1234            "h", "i", "j", "k", "l", "ł", "m", "n", "ń", "o",
1235            "ó", "p", "q", "r", "s", "ś", "t", "u", "v", "w",
1236            "x", "y", "z", "ź", "ż",
1237
1238            "A", "Ą", "B", "C", "Ć", "D", "E", "Ę", "F", "G",
1239            "H", "I", "J", "K", "L", "Ł", "M", "N", "Ń", "O",
1240            "Ó", "P", "Q", "R", "S", "Ś", "T", "U", "V", "W",
1241            "X", "Y", "Z", "Ź", "Ż",
1242        },
1243        cz = { -- czech
1244            "a", "á", "b", "c", "č", "d", "ď", "e", "é", "ě",
1245            "f", "g", "h", "i", "í", "j", "k", "l", "m",
1246            "n", "ň", "o", "ó", "p", "q", "r", "ř", "s", "š",
1247            "t", "ť", "u", "ú",  "ů", "v", "w", "x",  "y", "ý",
1248            "z", "ž",
1249
1250            "A", "Á", "B", "C", "Č", "D", "Ď", "E", "É", "Ě",
1251            "F", "G", "H", "I", "Í", "J", "K", "L", "M",
1252            "N", "Ň", "O", "Ó", "P", "Q", "R", "Ř", "S", "Š",
1253            "T", "Ť", "U", "Ú",  "Ů", "V", "W", "X",  "Y", "Ý",
1254            "Z", "Ž",
1255        },
1256        sk = { -- slovak
1257            "a", "á", "ä", "b", "c", "č", "d", "ď",
1258            "e", "é", "f", "g", "h", ch,  "i", "í", "j", "k",
1259            "l", "ĺ", "ľ", "m", "n", "ň", "o", "ó", "ô", "p",
1260            "q", "r", "ŕ", "s", "š", "t", "ť", "u", "ú", "v",
1261            "w", "x", "y", "ý", "z", "ž",
1262
1263            "A", "Á", "Ä", "B", "C", "Č", "D", "Ď",
1264            "E", "É", "F", "G", "H", "I", "Í", "J", "K",
1265            "L", "Ĺ", "Ľ", "M", "N", "Ň", "O", "Ó", "Ô", "P",
1266            "Q", "R", "Ŕ", "S", "Š", "T", "Ť", "U", "Ú", "V",
1267            "W", "X", "Y", "Ý", "Z", "Ž",
1268        },
1269        hr = { -- croatian
1270            "a", "b", "c", "č", "ć", "d", "đ", "e", "f",
1271            "g", "h", "i", "j", "k", "l", "m", "n",
1272            "o", "p", "r", "s", "š", "t", "u", "v", "z", "ž",
1273
1274            "A", "B", "C", "Č", "Ć", "D", "Đ", "E", "F",
1275            "G", "H", "I", "J", "K", "L", "M", "N",
1276            "O", "P", "R", "S", "Š", "T", "U", "V", "Z", "Ž",
1277        },
1278        sr = { -- serbian
1279            "а", "б", "в", "г", "д", "ђ", "е", "ж", "з", "и",
1280            "ј", "к", "л", "љ", "м", "н", "њ", "о", "п", "р",
1281            "с", "т", "ћ", "у", "ф", "х", "ц", "ч", "џ", "ш",
1282
1283            "А", "Б", "В", "Г", "Д", "Ђ", "Е", "Ж", "З", "И",
1284            "Ј", "К", "Л", "Љ", "М", "Н", "Њ", "О", "П", "Р",
1285            "С", "Т", "Ћ", "У", "Ф", "Х", "Ц", "Ч", "Џ", "Ш",
1286        },
1287        no = { -- norwegian
1288            "a", "b", "c", "d", "e", "f", "g", "h", "i", "j",
1289            "k", "l", "m", "n", "o", "p", "q", "r", "s", "t",
1290            "u", "v", "w", "x", "y", "z", "æ", "ø", "å",
1291
1292            "A", "B", "C", "D", "E", "F", "G", "H", "I", "J",
1293            "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T",
1294            "U", "V", "W", "X", "Y", "Z", "Æ", "Ø", "Å",
1295        },
1296        da = { --danish
1297            "a", "b", "c", "d", "e", "f", "g", "h", "i", "j",
1298            "k", "l", "m", "n", "o", "p", "q", "r", "s", "t",
1299            "u", "v", "w", "x", "y", "z", "æ", "ø", "å",
1300
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        sv = { -- swedish
1306            "a", "b", "c", "d", "e", "f", "g", "h", "i", "j",
1307            "k", "l", "m", "n", "o", "p", "q", "r", "s", "t",
1308            "u", "v", "w", "x", "y", "z", "å", "ä", "ö",
1309
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        is = { -- islandic
1315            "a", "á", "b", "d", "ð", "e", "é", "f", "g", "h",
1316            "i", "í", "j", "k", "l", "m", "n", "o", "ó", "p",
1317            "r", "s", "t", "u", "ú", "v", "x", "y", "ý", "þ",
1318            "æ", "ö",
1319
1320            "A", "Á", "B", "D", "Ð", "E", "É", "F", "G", "H",
1321            "I", "Í", "J", "K", "L", "M", "N", "O", "Ó", "P",
1322            "R", "S", "T", "U", "Ú", "V", "X", "Y", "Ý", "Þ",
1323            "Æ", "Ö",
1324        },
1325     -- gr = { -- greek
1326     --     "α", "ά", "ὰ", "ᾶ", "ᾳ", "ἀ", "ἁ", "ἄ", "ἂ", "ἆ",
1327     --     "ἁ", "ἅ", "ἃ", "ἇ", "ᾁ", "ᾴ", "ᾲ", "ᾷ", "ᾄ", "ᾂ",
1328     --     "ᾅ", "ᾃ", "ᾆ", "ᾇ", "β", "γ", "δ", "ε", "έ", "ὲ",
1329     --     "ἐ", "ἔ", "ἒ", "ἑ", "ἕ", "ἓ", "ζ", "η", "η", "ή",
1330     --     "ὴ", "ῆ", "ῃ", "ἠ", "ἤ", "ἢ", "ἦ", "ᾐ", "ἡ", "ἥ",
1331     --     "ἣ", "ἧ", "ᾑ", "ῄ", "ῂ", "ῇ", "ᾔ", "ᾒ", "ᾕ", "ᾓ",
1332     --     "ᾖ", "ᾗ", "θ", "ι", "ί", "ὶ", "ῖ", "ἰ", "ἴ", "ἲ",
1333     --     "ἶ", "ἱ", "ἵ", "ἳ", "ἷ", "ϊ", "ΐ", "ῒ", "ῗ", "κ",
1334     --     "λ", "μ", "ν", "ξ", "ο", "ό", "ὸ", "ὀ", "ὄ", "ὂ",
1335     --     "ὁ", "ὅ", "ὃ", "π", "ρ", "ῤ", "ῥ", "σ", "ς", "τ",
1336     --     "υ", "ύ", "ὺ", "ῦ", "ὐ", "ὔ", "ὒ", "ὖ", "ὑ", "ὕ",
1337     --     "ὓ", "ὗ", "ϋ", "ΰ", "ῢ", "ῧ", "φ", "χ", "ψ", "ω",
1338     --     "ώ", "ὼ", "ῶ", "ῳ", "ὠ", "ὤ", "ὢ", "ὦ", "ᾠ", "ὡ",
1339     --     "ὥ", "ὣ", "ὧ", "ᾡ", "ῴ", "ῲ", "ῷ", "ᾤ", "ᾢ", "ᾥ",
1340     --     "ᾣ", "ᾦ", "ᾧ",
1341     --
1342     --     "Α", "Ά", "Ὰ", "Α͂", "Ἀ", "Ἁ", "Ἄ", "Ἂ", "Ἆ",
1343     --     "Ἁ", "Ἅ", "Ἃ", "Ἇ",
1344     --     "Β", "Γ", "Δ", "Ε", "Έ", "Ὲ",
1345     --     "Ἐ", "Ἔ", "Ἒ", "Ἑ", "Ἕ", "Ἓ", "Ζ", "Η", "Η", "Ή",
1346     --     "Ὴ", "Η͂", "Ἠ", "Ἤ", "Ἢ", "Ἦ", "Ἡ", "Ἥ",
1347     --     "Ἣ", "Ἧ",
1348     --     "Θ", "Ι", "Ί", "Ὶ", "Ι͂", "Ἰ", "Ἴ", "Ἲ",
1349     --     "Ἶ", "Ἱ", "Ἵ", "Ἳ", "Ἷ", "Ϊ", "Ϊ́", "Ϊ̀", "Ϊ͂", "Κ",
1350     --     "Λ", "Μ", "Ν", "Ξ", "Ο", "Ό", "Ὸ", "Ὀ", "Ὄ", "Ὂ",
1351     --     "Ὁ", "Ὅ", "Ὃ", "Π", "Ρ", "Ρ̓", "Ῥ", "Σ", "Σ", "Τ",
1352     --     "Υ", "Ύ", "Ὺ", "Υ͂", "Υ̓", "Υ̓́", "Υ̓̀", "Υ̓͂", "Ὑ", "Ὕ",
1353     --     "Ὓ", "Ὗ", "Ϋ", "Ϋ́", "Ϋ̀", "Ϋ͂", "Φ", "Χ", "Ψ", "Ω",
1354     --     "Ώ", "Ὼ", "Ω͂", "Ὠ", "Ὤ", "Ὢ", "Ὦ", "Ὡ",
1355     --     "Ὥ", "Ὣ", "Ὧ",
1356     --     },
1357        gr = { -- greek
1358            "α", "β", "γ", "δ", "ε", "ζ", "η", "θ", "ι", "κ",
1359            "λ", "μ", "ν", "ξ", "ο", "π", "ρ", "ς", "τ", "υ",
1360            "φ", "χ", "ψ", "ω",
1361
1362            "Α", "Β", "Γ", "Δ", "Ε", "Ζ", "Η", "Θ", "Ι", "Κ",
1363            "Λ", "Μ", "Ν", "Ξ", "Ο", "Π", "Ρ", "Σ", "Τ", "Υ",
1364            "Χ", "Ψ", "Ω",
1365            },
1366        la = { -- latin
1367            "a", "ā", "ă", "b", "c", "d", "e", "ē", "ĕ", "f",
1368            "g", "h", "i", "ī", "ĭ", "j", "k", "l", "m", "n",
1369            "o", "ō", "ŏ", "p", "q", "r", "s", "t", "u", "ū",
1370            "ŭ", "v", "w", "x", "y", "ȳ", "", "z", "æ",
1371
1372            "A", "Ā", "Ă", "B", "C", "D", "E", "Ē", "Ĕ", "F",
1373            "G", "H", "I", "Ī", "Ĭ", "J", "K", "L", "M", "N",
1374            "O", "Ō", "Ŏ", "P", "Q", "R", "S", "T", "U", "Ū",
1375            "Ŭ", "V", "W", "X", "Y", "Ȳ", "", "Z", "Æ",
1376        },
1377        it = { -- italian
1378            "a", "á", "b", "c", "d", "e", "é", "è", "f", "g",
1379            "h", "i", "í", "ì", "j", "k", "l", "m", "n", "o",
1380            "ó", "ò", "p", "q", "r", "s", "t", "u", "ú", "ù",
1381            "v", "w", "x", "y", "z",
1382
1383            "A", "Á", "B", "C", "D", "E", "É", "È", "F", "G",
1384            "H", "I", "Í", "Ì", "J", "K", "L", "M", "N", "O",
1385            "Ó", "Ò", "P", "Q", "R", "S", "T", "U", "Ú", "Ù",
1386            "V", "W", "X", "Y", "Z",
1387        },
1388        ro = { -- romanian
1389            "a", "ă", "â", "b", "c", "d", "e", "f", "g", "h",
1390            "i", "î", "j", "k", "l", "m", "n", "o", "p", "q",
1391            "r", "s", "ș", "t", "ț", "u", "v", "w", "x", "y",
1392            "z",
1393
1394            "A", "Ă", "Â", "B", "C", "D", "E", "F", "G", "H",
1395            "I", "Î", "J", "K", "L", "M", "N", "O", "P", "Q",
1396            "R", "S", "Ș", "T", "Ț", "U", "V", "W", "X", "Y",
1397            "Z",
1398        },
1399        es = { -- spanish
1400            "a", "á", "b", "c", "d", "e", "é", "f", "g", "h",
1401            "i", "í", "j", "k", "l", "m", "n", "ñ", "o", "ó",
1402            "p", "q", "r", "s", "t", "u", "ú", "ü", "v", "w",
1403            "x", "y", "z",
1404
1405            "A", "Á", "B", "C", "D", "E", "É", "F", "G", "H",
1406            "I", "Í", "J", "K", "L", "M", "N", "Ñ", "O", "Ó",
1407            "P", "Q", "R", "S", "T", "U", "Ú", "Ü", "V", "W",
1408            "X", "Y", "Z",
1409        },
1410        pt = { -- portuguese
1411            "a", "á", "â", "ã", "à", "b", "c", "ç", "d", "e",
1412            "é", "ê", "f", "g", "h", "i", "í", "j", "k", "l",
1413            "m", "n", "o", "ó", "ô", "õ", "p", "q", "r", "s",
1414            "t", "u", "ú", "ü", "v", "w", "x", "y", "z",
1415
1416            "A", "Á", "Â", "Ã", "À", "B", "C", "Ç", "D", "E",
1417            "É", "Ê", "F", "G", "H", "I", "Í", "J", "K", "L",
1418            "M", "N", "O", "Ó", "Ô", "Õ", "P", "Q", "R", "S",
1419            "T", "U", "Ú", "Ü", "V", "W", "X", "Y", "Z",
1420        },
1421        lt = { -- lithuanian
1422            "a", "ą", "b", "c", "ch",  "č", "d", "e", "ę", "ė",
1423            "f", "g", "h", "i", "į", "y", "j", "k", "l", "m",
1424            "n", "o", "p", "r", "s", "š", "t", "u", "ų", "ū",
1425            "v", "z", "ž",
1426
1427            "A", "Ą", "B", "C", "CH",  "Č", "D", "E", "Ę", "Ė",
1428            "F", "G", "H", "I", "Į", "Y", "J", "K", "L", "M",
1429            "N", "O", "P", "R", "S", "Š", "T", "U", "Ų", "Ū",
1430            "V", "Z", "Ž",
1431        },
1432        lv = { -- latvian
1433            "a", "ā", "b", "c", "č", "d", "e", "ē", "f", "g",
1434            "ģ", "h", "i", "ī", "j", "k", "ķ", "l", "ļ", "m",
1435            "n", "ņ", "o", "ō", "p", "r", "ŗ", "s", "š", "t",
1436            "u", "ū", "v", "z", "ž",
1437
1438            "A", "Ā", "B", "C", "Č", "D", "E", "Ē", "F", "G",
1439            "Ģ", "H", "I", "Ī", "J", "K", "Ķ", "L", "Ļ", "M",
1440            "N", "Ņ", "O", "Ō", "P", "R", "Ŗ", "S", "Š", "T",
1441            "U", "Ū", "V", "Z", "Ž",
1442        },
1443        hu = { -- hungarian
1444            "a", "á", "b", "c", "d", "e", "é",
1445            "f", "g", "h", "i", "í", "j", "k", "l",
1446            "m", "n", "o", "ó", "ö", "ő", "p", "q", "r",
1447            "s",  "t", "u", "ú", "ü", "ű", "v", "w",
1448            "x", "y", "z",
1449
1450            "A", "Á", "B", "C", "D", "E", "É",
1451            "F", "G", "H", "I", "Í", "J", "K", "L",
1452            "M", "N", "O", "Ó", "Ö", "Ő", "P", "Q", "R",
1453            "S",  "T", "U", "Ú", "Ü", "Ű", "V", "W",
1454            "X", "Y", "Z",
1455        },
1456        et = { -- estonian
1457            "a", "b", "d", "e", "f", "g", "h", "i", "j", "k",
1458            "l", "m", "n", "o", "p", "r", "s", "š", "z", "ž",
1459            "t", "u", "v", "w", "õ", "ä", "ö", "ü", "x", "y",
1460
1461            "A", "B", "D", "E", "F", "G", "H", "I", "J", "K",
1462            "L", "M", "N", "O", "P", "R", "S", "Š", "Z", "Ž",
1463            "T", "U", "V", "W", "Õ", "Ä", "Ö", "Ü", "X", "Y",
1464        },
1465     -- jp = { -- japanese
1466     --     "あ", "い", "う", "え", "お", "か", "き", "く", "け", "こ",
1467     --     "さ", "し", "す", "せ", "そ", "た", "ち", "つ", "て", "と",
1468     --     "な", "に", "ぬ", "ね", "の", "は", "ひ", "ふ", "へ", "ほ",
1469     --     "ま", "み", "む", "め", "も", "や", "ゆ", "よ",
1470     --     "ら", "り", "る", "れ", "ろ", "わ", "ゐ", "ゑ", "を", "ん",
1471     -- },
1472    }
1473
1474    local textselector = { }
1475    for k, v in next, textlists do
1476        textselector[#textselector+1] = k
1477    end
1478    table.sort(textselector)
1479
1480    -- We can populate these with the utf converter but it looks nicer here to
1481    -- see what we actually get. And it also tests how SciTE displays these
1482    -- special characters.
1483
1484    local mathsets = {
1485        { "tf", {
1486            "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",
1487            "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",
1488            "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"
1489        }, },
1490        { "bf", {
1491            "𝐛", "𝐜", "𝐝", "𝐞", "𝐟", "𝐠", "𝐡", "𝐢", "𝐣", "𝐤", "𝐥", "𝐦", "𝐧", "𝐨", "𝐩", "𝐪", "𝐫", "𝐬", "𝐭", "𝐮", "𝐯", "𝐰", "𝐱", "𝐲", "𝐳",
1492            "𝐀", "𝐁", "𝐂", "𝐃", "𝐄", "𝐅", "𝐆", "𝐇", "𝐈", "𝐉", "𝐊", "𝐋", "𝐌", "𝐍", "𝐎", "𝐏", "𝐐", "𝐑", "𝐒", "𝐓", "𝐔", "𝐕", "𝐖", "𝐗", "𝐘", "𝐙", "𝐚",
1493            "𝟎", "𝟏", "𝟐", "𝟑", "𝟒", "𝟓", "𝟔", "𝟕", "𝟖", "𝟗"
1494        }, },
1495        { "it",           {
1496            "𝑎", "𝑏", "𝑐", "𝑑", "𝑒", "𝑓", "𝑔", "", "𝑖", "𝑗", "𝑘", "𝑙", "𝑚", "𝑛", "𝑜", "𝑝", "𝑞", "𝑟", "𝑠", "𝑡", "𝑢", "𝑣", "𝑤", "𝑥", "𝑦", "𝑧",
1497            "𝐴", "𝐵", "𝐶", "𝐷", "𝐸", "𝐹", "𝐺", "𝐻", "𝐼", "𝐽", "𝐾", "𝐿", "𝑀", "𝑁", "𝑂", "𝑃", "𝑄", "𝑅", "𝑆", "𝑇", "𝑈", "𝑉", "𝑊", "𝑋", "𝑌", "𝑍",
1498        }, },
1499        { "bi",           {
1500            "𝒂", "𝒃", "𝒄", "𝒅", "𝒆", "𝒇", "𝒈", "𝒉", "𝒊", "𝒋", "𝒌", "𝒍", "𝒎", "𝒏", "𝒐", "𝒑", "𝒒", "𝒓", "𝒔", "𝒕", "𝒖", "𝒗", "𝒘", "𝒙", "𝒚", "𝒛",
1501            "𝑨", "𝑩", "𝑪", "𝑫", "𝑬", "𝑭", "𝑮", "𝑯", "𝑰", "𝑱", "𝑲", "𝑳", "𝑴", "𝑵", "𝑶", "𝑷", "𝑸", "𝑹", "𝑺", "𝑻", "𝑼", "𝑽", "𝑾", "𝑿", "𝒀", "𝒁",
1502        }, },
1503        { "sc",       {
1504            "𝒵", "𝒶", "𝒷", "𝒸", "𝒹", "", "𝒻", "", "𝒽", "𝒾", "𝒿", "𝓀", "𝓁", "𝓂", "𝓃", "", "𝓅", "𝓆", "𝓇", "𝓈", "𝓉", "𝓊", "𝓋", "𝓌", "𝓍", "𝓎", "𝓏",
1505            "𝒜", "", "𝒞", "𝒟", "", "", "𝒢", "", "", "𝒥", "𝒦", "", "", "𝒩", "𝒪", "𝒫", "𝒬", "", "𝒮", "𝒯", "𝒰", "𝒱", "𝒲", "𝒳", "𝒴",
1506        }, },
1507        { "sc bf",   {
1508            "𝓪", "𝓫", "𝓬", "𝓭", "𝓮", "𝓯", "𝓰", "𝓱", "𝓲", "𝓳", "𝓴", "𝓵", "𝓶", "𝓷", "𝓸", "𝓹", "𝓺", "𝓻", "𝓼", "𝓽", "𝓾", "𝓿", "𝔀", "𝔁", "𝔂", "𝔃",
1509            "𝓐", "𝓑", "𝓒", "𝓓", "𝓔", "𝓕", "𝓖", "𝓗", "𝓘", "𝓙", "𝓚", "𝓛", "𝓜", "𝓝", "𝓞", "𝓟", "𝓠", "𝓡", "𝓢", "𝓣", "𝓤", "𝓥", "𝓦", "𝓧", "𝓨", "𝓩",
1510        }, },
1511        { "fr",      {
1512            "𝔞", "𝔟", "𝔠", "𝔡", "𝔢", "𝔣", "𝔤", "𝔥", "𝔦", "𝔧", "𝔨", "𝔩", "𝔪", "𝔫", "𝔬", "𝔭", "𝔮", "𝔯", "𝔰", "𝔱", "𝔲", "𝔳", "𝔴", "𝔵", "𝔶", "𝔷",
1513            "𝔄", "𝔅", "", "𝔇", "𝔈", "𝔉", "𝔊", "", "", "𝔍", "𝔎", "𝔏", "𝔐", "𝔑", "𝔒", "𝔓", "𝔔", "", "𝔖", "𝔗", "𝔘", "𝔙", "𝔚", "𝔛", "𝔜", "",
1514        }, },
1515        { "ds", {
1516            "𝕓", "𝕔", "𝕕", "𝕖", "𝕗", "𝕘", "𝕙", "𝕚", "𝕛", "𝕜", "𝕝", "𝕞", "𝕟", "𝕠", "𝕡", "𝕢", "𝕣", "𝕤", "𝕥", "𝕦", "𝕧", "𝕨", "𝕩", "𝕪", "𝕫",
1517            "𝔸", "𝔹", "", "𝔻", "𝔼", "𝔽", "𝔾", "", "𝕀", "𝕁", "𝕂", "𝕃", "𝕄", "", "𝕆", "", "", "", "𝕊", "𝕋", "𝕌", "𝕍", "𝕎", "𝕏", "𝕐", "", "𝕒",
1518            "𝟘", "𝟙", "𝟚", "𝟛", "𝟜", "𝟝", "𝟞", "𝟟", "𝟠", "𝟡"
1519        }, },
1520        { "fr bf",  {
1521            "𝕬", "𝕭", "𝕮", "𝕯", "𝕰", "𝕱", "𝕲", "𝕳", "𝕴", "𝕵", "𝕶", "𝕷", "𝕸", "𝕹", "𝕺", "𝕻", "𝕼", "𝕽", "𝕾", "𝕿", "𝖀", "𝖁", "𝖂", "𝖃",
1522            "𝖄", "𝖅", "𝖆", "𝖇", "𝖈", "𝖉", "𝖊", "𝖋", "𝖌", "𝖍", "𝖎", "𝖏", "𝖐", "𝖑", "𝖒", "𝖓", "𝖔", "𝖕", "𝖖", "𝖗", "𝖘", "𝖙", "𝖚", "𝖛", "𝖜", "𝖝", "𝖞", "𝖟"
1523        }, },
1524        { "ss tf",        {
1525            "𝖺", "𝖻", "𝖼", "𝖽", "𝖾", "𝖿", "𝗀", "𝗁", "𝗂", "𝗃", "𝗄", "𝗅", "𝗆", "𝗇", "𝗈", "𝗉", "𝗊", "𝗋", "𝗌", "𝗍", "𝗎", "𝗏", "𝗐", "𝗑", "𝗒", "𝗓",
1526            "𝖠", "𝖡", "𝖢", "𝖣", "𝖤", "𝖥", "𝖦", "𝖧", "𝖨", "𝖩", "𝖪", "𝖫", "𝖬", "𝖭", "𝖮", "𝖯", "𝖰", "𝖱", "𝖲", "𝖳", "𝖴", "𝖵", "𝖶", "𝖷", "𝖸", "𝖹",
1527            "𝟢", "𝟣", "𝟤", "𝟥", "𝟦", "𝟧", "𝟨", "𝟩", "𝟪", "𝟫"
1528        }, },
1529        { "ss bf",        {
1530            "𝗮", "𝗯", "𝗰", "𝗱", "𝗲", "𝗳", "𝗴", "𝗵", "𝗶", "𝗷", "𝗸", "𝗹", "𝗺", "𝗻", "𝗼", "𝗽", "𝗾", "𝗿", "𝘀", "𝘁", "𝘂", "𝘃", "𝘄", "𝘅", "𝘆", "𝘇",
1531            "𝗔", "𝗕", "𝗖", "𝗗", "𝗘", "𝗙", "𝗚", "𝗛", "𝗜", "𝗝", "𝗞", "𝗟", "𝗠", "𝗡", "𝗢", "𝗣", "𝗤", "𝗥", "𝗦", "𝗧", "𝗨", "𝗩", "𝗪", "𝗫", "𝗬", "𝗭",
1532            "𝟬", "𝟭", "𝟮", "𝟯", "𝟰", "𝟱", "𝟲", "𝟳", "𝟴", "𝟵",
1533        }, },
1534        { "ss it",        {
1535            "𝘢", "𝘣", "𝘤", "𝘥", "𝘦", "𝘧", "𝘨", "𝘩", "𝘪", "𝘫", "𝘬", "𝘭", "𝘮", "𝘯", "𝘰", "𝘱", "𝘲", "𝘳", "𝘴", "𝘵", "𝘶", "𝘷", "𝘸", "𝘹", "𝘺", "𝘻",
1536            "𝘈", "𝘉", "𝘊", "𝘋", "𝘌", "𝘍", "𝘎", "𝘏", "𝘐", "𝘑", "𝘒", "𝘓", "𝘔", "𝘕", "𝘖", "𝘗", "𝘘", "𝘙", "𝘚", "𝘛", "𝘜", "𝘝", "𝘞", "𝘟", "𝘠", "𝘡",
1537        }, },
1538        { "ss bi",        {
1539            "𝙖", "𝙗", "𝙘", "𝙙", "𝙚", "𝙛", "𝙜", "𝙝", "𝙞", "𝙟", "𝙠", "𝙡", "𝙢", "𝙣", "𝙤", "𝙥", "𝙦", "𝙧", "𝙨", "𝙩", "𝙪", "𝙫", "𝙬", "𝙭", "𝙮", "𝙯",
1540            "𝘼", "𝘽", "𝘾", "𝘿", "𝙀", "𝙁", "𝙂", "𝙃", "𝙄", "𝙅", "𝙆", "𝙇", "𝙈", "𝙉", "𝙊", "𝙋", "𝙌", "𝙍", "𝙎", "𝙏", "𝙐", "𝙑", "𝙒", "𝙓", "𝙔", "𝙕",
1541        }, },
1542        { "tt",           {
1543            "𝚊", "𝚋", "𝚌", "𝚍", "𝚎", "𝚏", "𝚐", "𝚑", "𝚒", "𝚓", "𝚔", "𝚕", "𝚖", "𝚗", "𝚘", "𝚙", "𝚚", "𝚛", "𝚜", "𝚝", "𝚞", "𝚟", "𝚠", "𝚡", "𝚢", "𝚣",
1544            "𝙰", "𝙱", "𝙲", "𝙳", "𝙴", "𝙵", "𝙶", "𝙷", "𝙸", "𝙹", "𝙺", "𝙻", "𝙼", "𝙽", "𝙾", "𝙿", "𝚀", "𝚁", "𝚂", "𝚃", "𝚄", "𝚅", "𝚆", "𝚇", "𝚈", "𝚉",
1545            "𝟶", "𝟷", "𝟸", "𝟹", "𝟺", "𝟻", "𝟼", "𝟽", "𝟾", "𝟿"
1546        }, },
1547        { "gr tf",        {
1548            "α", "β", "γ", "δ", "ε", "ζ", "η", "θ", "ι", "κ", "λ", "μ", "ν", "ξ", "ο", "π", "ρ", "ς", "σ", "τ", "υ", "φ", "χ", "ψ", "ω",
1549            "Α", "Β", "Γ", "Δ", "Ε", "Ζ", "Η", "Θ", "Ι", "Κ", "Λ", "Μ", "Ν", "Ξ", "Ο", "Π", "Ρ", "΢", "Σ", "Τ", "Υ", "Φ", "Χ", "Ψ", "Ω",
1550        }, },
1551        { "gr bf",        {
1552            "𝛂", "𝛃", "𝛄", "𝛅", "𝛆", "𝛇", "𝛈", "𝛉", "𝛊", "𝛋", "𝛌", "𝛍", "𝛎", "𝛏", "𝛐", "𝛑", "𝛒", "𝛓", "𝛔", "𝛕", "𝛖", "𝛗", "𝛘", "𝛙", "𝛚",
1553            "𝚨", "𝚩", "𝚪", "𝚫", "𝚬", "𝚭", "𝚮", "𝚯", "𝚰", "𝚱", "𝚲", "𝚳", "𝚴", "𝚵", "𝚶", "𝚷", "𝚸", "𝚹", "𝚺", "𝚻", "𝚼", "𝚽", "𝚾", "𝚿", "𝛀",
1554        }, },
1555        { "gr it",        {
1556            "𝛼", "𝛽", "𝛾", "𝛿", "𝜀", "𝜁", "𝜂", "𝜃", "𝜄", "𝜅", "𝜆", "𝜇", "𝜈", "𝜉", "𝜊", "𝜋", "𝜌", "𝜍", "𝜎", "𝜏", "𝜐", "𝜑", "𝜒", "𝜓", "𝜔",
1557            "𝛢", "𝛣", "𝛤", "𝛥", "𝛦", "𝛧", "𝛨", "𝛩", "𝛪", "𝛫", "𝛬", "𝛭", "𝛮", "𝛯", "𝛰", "𝛱", "𝛲", "𝛳", "𝛴", "𝛵", "𝛶", "𝛷", "𝛸", "𝛹", "𝛺",
1558        }, },
1559        { "gr bi",        {
1560            "𝜶", "𝜷", "𝜸", "𝜹", "𝜺", "𝜻", "𝜼", "𝜽", "𝜾", "𝜿", "𝝀", "𝝁", "𝝂", "𝝃", "𝝄", "𝝅", "𝝆", "𝝇", "𝝈", "𝝉", "𝝊", "𝝋", "𝝌", "𝝍", "𝝎",
1561            "𝜜", "𝜝", "𝜞", "𝜟", "𝜠", "𝜡", "𝜢", "𝜣", "𝜤", "𝜥", "𝜦", "𝜧", "𝜨", "𝜩", "𝜪", "𝜫", "𝜬", "𝜭", "𝜮", "𝜯", "𝜰", "𝜱", "𝜲", "𝜳", "𝜴",
1562        }, },
1563        { "gr ss bf",     {
1564            "𝝰", "𝝱", "𝝲", "𝝳", "𝝴", "𝝵", "𝝶", "𝝷", "𝝸", "𝝹", "𝝺", "𝝻", "𝝼", "𝝽", "𝝾", "𝝿", "𝞀", "𝞁", "𝞂", "𝞃", "𝞄", "𝞅", "𝞆", "𝞇", "𝞈",
1565            "𝝖", "𝝗", "𝝘", "𝝙", "𝝚", "𝝛", "𝝜", "𝝝", "𝝞", "𝝟", "𝝠", "𝝡", "𝝢", "𝝣", "𝝤", "𝝥", "𝝦", "𝝧", "𝝨", "𝝩", "𝝪", "𝝫", "𝝬", "𝝭", "𝝮",
1566        }, },
1567        { "gr ss bi",  {
1568            "𝞪", "𝞫", "𝞬", "𝞭", "𝞮", "𝞯", "𝞰", "𝞱", "𝞲", "𝞳", "𝞴", "𝞵", "𝞶", "𝞷", "𝞸", "𝞹", "𝞺", "𝞻", "𝞼", "𝞽", "𝞾", "𝞿", "𝟀", "𝟁", "𝟂",
1569            "𝞐", "𝞑", "𝞒", "𝞓", "𝞔", "𝞕", "𝞖", "𝞗", "𝞘", "𝞙", "𝞚", "𝞛", "𝞜", "𝞝", "𝞞", "𝞟", "𝞠", "𝞡", "𝞢", "𝞣", "𝞤", "𝞥", "𝞦", "𝞧", "𝞨",
1570        }, },
1571        { "op", {
1572        }, },
1573        { "sy a", {
1574        }, },
1575        { "sy b", {
1576        }, },
1577        { "sy c", {
1578        }, },
1579    }
1580
1581    local mathlists    = { }
1582    local mathselector = { }
1583
1584    for i=1,#mathsets do
1585        local mathset = mathsets[i]
1586        mathselector[#mathselector+1] = mathset[1]
1587        mathlists[mathset[1]] = mathset[2]
1588    end
1589
1590    local enabled   = 0
1591    local usedlists = {
1592        { name = "text", current = "en", lists = textlists, selector = textselector },
1593        { name = "math", current = "tf", lists = mathlists, selector = mathselector },
1594    }
1595
1596    local function make_strip()
1597        local used     = usedlists[enabled]
1598        local lists    = used.lists
1599        local alphabet = lists[used.current]
1600        local selector = "(hide)(" .. concat(used.selector,")(") .. ")"
1601        local alphabet = "(" .. used.current .. ":)(" .. concat(alphabet,")(") .. ")"
1602        scite.StripShow(selector .. "\n" .. alphabet)
1603    end
1604
1605    local function hide_strip()
1606        scite.StripShow("")
1607    end
1608
1609    local function process_strip(control)
1610        local value = scite.StripValue(control)
1611        if value == "hide" then
1612            hide_strip()
1613            return
1614        elseif find(value,".+:") then
1615            return
1616        end
1617        local used = usedlists[enabled]
1618        if used.lists[value] then
1619            used.current = value
1620            make_strip()
1621        else
1622            editor:insert(editor.CurrentPos,value)
1623        end
1624    end
1625
1626    local function ignore_strip()
1627    end
1628
1629    function toggle_strip(name)
1630        enabled = enabled + 1
1631        if usedlists[enabled] then
1632            make_strip()
1633            OnStrip = process_strip
1634        else
1635            enabled = 0
1636            hide_strip()
1637            OnStrip = ignore_strip
1638        end
1639    end
1640
1641end
1642
1643-- Last time I checked the source the output pane errorlist lexer was still
1644-- hardcoded and could not be turned off ... alas.
1645
1646-- output.Lexer = 0
1647
1648-- SCI_SETBIDIRECTIONAL = SC_BIDIRECTIONAL_R2L
1649
1650-- Because SCITE messes around with package.loaded a regular require doesn't work, so
1651-- we overload it. We also add some paths.
1652
1653do
1654
1655    package.path = props.SciteDefaultHome .. "/context/lexers/?.lua;"        .. package.path
1656    package.path = props.SciteDefaultHome .. "/context/lexers/themes/?.lua;" .. package.path
1657    package.path = props.SciteDefaultHome .. "/context/lexers/data/?.lua;"   .. package.path
1658
1659    local required = require
1660    local loaded   = { }
1661
1662    require = function(name)
1663        local data = loaded[name]
1664        if not data then
1665            data = required(name)
1666            loaded[name] = data
1667        end
1668        return data
1669    end
1670
1671end
1672
1673-- It makes not much sense to trace back over whitespace and start lexing because in
1674-- our use case we can have nested lexers that themselve need a trace back. Also, in
1675-- large documents we seldom add at the end and therefore can as well parse the
1676-- whole document. Lua 5.4 is faster anyway.
1677--
1678-- The 'editor' object is not useable because (1) it is null terminating which is
1679-- bad for the PDF lexer. The 'styler' on the other hand is utf based and does not
1680-- work well for the byte based LPEG lexers. And, because 'OnStyle' creates a large
1681-- userdata blob anyway, we added a few methods to it.
1682--
1683-- Because this file will be reloaded after a change, and in the process messes with
1684-- some global properties (like package.loaded) we have some require hackery in the
1685-- lexer files.
1686
1687-- function OnStyle(styler)
1688--     local S_DEFAULT = 0
1689--     local S_IDENTIFIER = 1
1690--     local S_KEYWORD = 2
1691--     local S_UNICODECOMMENT = 3
1692--     local identifierCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
1693--     styler:StartStyling(styler.startPos, styler.lengthDoc, styler.initStyle)
1694--     while styler:More() do
1695--         if styler:State() == S_IDENTIFIER then
1696--             if not identifierCharacters:find(styler:Current(), 1, true) then
1697--                 local identifier = styler:Token()
1698--                 if identifier == "if" or identifier == "end" then
1699--                         styler:ChangeState(S_KEYWORD)
1700--                 end
1701--                 styler:SetState(S_DEFAULT)
1702--             end
1703--         elseif styler:State() == S_UNICODECOMMENT then
1704--             if styler:Match("»") then
1705--                 styler:ForwardSetState(S_DEFAULT)
1706--             end
1707--         end
1708--         if styler:State() == S_DEFAULT then
1709--             if styler:Match("«") then
1710--                 styler:SetState(S_UNICODECOMMENT)
1711--             elseif identifierCharacters:find(styler:Current(), 1, true) then
1712--                 styler:SetState(S_IDENTIFIER)
1713--             end
1714--         end
1715--         styler:Forward()
1716--     end
1717--     styler:EndStyling()
1718-- end
1719
1720-- function OnStyle(styler)
1721--     local lineStart = editor:LineFromPosition(styler.startPos)
1722--     local lineEnd = editor:LineFromPosition(styler.startPos + styler.lengthDoc)
1723--     editor:StartStyling(styler.startPos, 31)
1724--     for line=lineStart,lineEnd,1 do
1725--         local lengthLine = editor:PositionFromLine(line+1) - editor:PositionFromLine(line)
1726--         local lineText = editor:GetLine(line)
1727--         local first = string.sub(lineText,1,1)
1728--         local style = 0
1729--         if first == "+" then
1730--                 style = 1
1731--         elseif first == " " or first == "\t" then
1732--                 style = 2
1733--         end
1734--         editor:SetStyling(lengthLine, style)
1735--     end
1736-- end
1737
1738do
1739
1740    local lexers     = nil
1741    local properties = props
1742    local partial    = false
1743    local partial    = true
1744    local trace      = false
1745--     local trace      = true
1746
1747    local loadedlexers = setmetatable ( { }, {
1748        __index = function(t,k)
1749                local language = match(k,"^script_(.*)$") or k
1750                if not lexers then
1751                    lexers = require("scite-context-lexer")
1752                    lexers.loadtheme(require("scite-context-theme"))
1753                end
1754                local name = "scite-context-lexer-" .. language
1755                local v = lexers.load(name)
1756                if v then
1757                    lexers.registertheme(properties,language)
1758                else
1759                    v = false
1760                end
1761                t[name]     = v
1762                t[k]        = v
1763                t[language] = v
1764                return v
1765            end
1766        } )
1767
1768    local function update(language,size,start,stop)
1769        if language then
1770            local syntax = loadedlexers[language]
1771            if syntax then
1772                lexers.scite_onstyle(syntax,editor,partial,language,props.FileNameExt,size,start,stop,trace)
1773            end
1774        end
1775    end
1776
1777    function Initialise()
1778        check_output_pane()
1779    end
1780
1781    function OnStyle(styler)
1782        -- for the moment here: editor.StyleClearAll(output) -- we have no way to nil the output lexer
1783        update(styler.language,editor.TextLength,styler.startPos,styler.lengthDoc)
1784    end
1785
1786    function OnOpen(filename)
1787        if trace then
1788            report("opening '%s' of %i bytes, language '%s'",filename,editor.TextLength,props.Language)
1789        end
1790        update(props.Language,editor.TextLength,0,editor.TextLength)
1791        check_output_pane()
1792    end
1793
1794    function OnSwitchFile(filename)
1795        if dirty[props.FileNameExt] then
1796            if trace then
1797                report("switching '%s' of %i bytes, language '%s'",filename,editor.TextLength,props.Language)
1798            end
1799            update(props.Language,editor.TextLength,0,editor.TextLength)
1800            dirty[props.FileNameExt] = false
1801        end
1802        check_output_pane()
1803    end
1804
1805    function OnChar()
1806        if not editor:AutoCActive() then
1807            local syntax = loadedlexers[props.Language]
1808            if syntax and syntax.completion then
1809                local stop   = editor.CurrentPos
1810                local start  = editor:WordStartPosition(stop,true)
1811                local length = stop - start
1812                if length >= 2 then
1813                    local snippet = editor:textrange(start,stop)
1814                    local list    = syntax.completion(snippet)
1815                    if list then
1816                        editor.AutoCMaxHeight = 30
1817                        editor.AutoCSeparator = 32
1818                        editor:AutoCShow(length,list)
1819                    end
1820                end
1821            end
1822        end
1823    end
1824
1825end
1826
1827-- function OnKey(a,b,c)
1828--     print("key",a,b,c)
1829-- end
1830
1831