local info = { version = 1.002, comment = "file handler for textadept for context/metafun", author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", copyright = "PRAGMA ADE / ConTeXt Development Team", license = "see context related readme files", } local lexer = require("scite-context-lexer") local context = lexer.context local char, format, gsub = string.char, string.format, string.gsub -- What is _CHARSET doing ... I don't want any messing with conversion at all. Scite is -- more clever with e.g. pdf. How can I show non ascii as escapes. -- I'll add a few more keybindings. I mostly made this file for my own use and as a -- fallback for SciTE as it runs on all os's. It might evolve ... who knows. io.encodings = { "UTF-8", "ASCII", "UTF-16", } -- We need this for for instance pdf files (faster too): local sevenbitascii = { } for i=127,255 do sevenbitascii[char(i)] = format("0x%02X",i) end local function setsevenbitascii(buffer) -- we cannot directly assign sevenbitascii to buffer local representation = buffer.representation for k, v in next, sevenbitascii do representation[k] = v end end -- Here we rebind keys. For this we need to load the alternative runner framework. I will -- probably change the menu. local oldrunner = textadept.run local runner = require("textadept-context-runner") -- local function userunner(runner) -- -- -- keys [OSX and 'mr' or 'cr' ] = runner.process or runner.run -- keys [OSX and 'mR' or (GUI and 'cR' or 'cmr')] = runner.check or runner.compile -- keys [OSX and 'mB' or (GUI and 'cB' or 'cmb')] = runner.preview or runner.build -- keys [OSX and 'mX' or (GUI and 'cX' or 'cmx')] = runner.quit or runner.stop -- -- -- textadept.menu.menubar [_L['_Tools']] [_L['_Run']] [2] = runner.process or runner.run -- textadept.menu.menubar [_L['_Tools']] [_L['_Compile']] [2] = runner.check or runner.compile -- textadept.menu.menubar [_L['_Tools']] [_L['Buil_d']] [2] = runner.preview or runner.build -- textadept.menu.menubar [_L['_Tools']] [_L['S_top']] [2] = runner.quit or runner.stop -- -- -- end -- I played a while with supporting both systems alongsize but getting the menus -- synchronized is a real pain and semi-random. So, I decided to just drop the -- old. And I don't want to implement a full variant now. Anyway, after that -- conclusion I decided to replace not only the tools menu. local SEPARATOR = { "" } local newmenu = { } local newkeys = { } do newmenu.file = { title = '_File', { '_New', buffer.new }, { '_Open', io.open_file }, { 'Open _Recent', io.open_recent_file }, { 'Re_load', io.reload_file }, { '_Save', io.save_file }, { 'Save _As', io.save_file_as }, { 'Save All', io.save_all_files }, SEPARATOR, { '_Close', io.close_buffer }, { 'Close All', io.close_all_buffers }, -- SEPARATOR, -- { 'Loa_d Session', textadept.session.load }, -- { 'Sav_e Session', textadept.session.save }, SEPARATOR, { _L['_Quit'], quit }, } -- maybe just the same keys on all ... or duplicate on osx newkeys[OSX and 'mn' or 'cn'] = buffer.new newkeys[OSX and 'mo' or 'co'] = io.open_file newkeys[OSX and 'cmo' or 'cao'] = io.open_recent_file newkeys[OSX and 'ms' or 'cs'] = io.save_file newkeys[OSX and 'mS' or 'cS'] = io.save_file_as newkeys[OSX and 'mw' or 'cw'] = io.close_buffer newkeys[OSX and 'mW' or 'cW'] = io.close_all_buffers end do local function complete_symbol() textadept.editing.autocomplete(buffer:get_lexer(true)) end newmenu.edit = { title = '_Edit', SEPARATOR, { '_Undo', buffer.undo }, { '_Redo', buffer.redo }, SEPARATOR, { 'Cu_t', buffer.cut }, { '_Copy', buffer.copy }, { '_Paste', buffer.paste }, { '_Delete', buffer.clear }, { 'Select _All', buffer.select_all }, SEPARATOR, { 'Duplicate _Line', buffer.line_duplicate }, SEPARATOR, { 'Toggle _Block Comment', textadept.editing.block_comment }, { '_Upper Case Selection', buffer.upper_case }, { '_Lower Case Selection', buffer.lower_case }, } newkeys[OSX and 'mz' or 'cz'] = buffer.undo newkeys[OSX and 'my' or 'cy'] = buffer.redo newkeys[OSX and 'mx' or 'cx'] = buffer.cut newkeys[OSX and 'mc' or 'cc'] = buffer.copy newkeys[OSX and 'mv' or 'cv'] = buffer.paste newkeys[OSX and 'ma' or 'ca'] = buffer.select_all newkeys[OSX and 'mD' or 'cD'] = textadept.editing.select_word newkeys[OSX and 'mN' or 'cN'] = textadept.editing.select_line newkeys[OSX and 'mP' or 'cP'] = textadept.editing.select_paragraph newkeys['del'] = buffer.clear newkeys['cy'] = buffer.redo newkeys[OSX and 'md' or 'cd'] = buffer.line_duplicate newkeys[OSX and 'cu' or 'cau'] = buffer.upper_case newkeys[OSX and 'cU' or 'caU'] = buffer.lower_case newkeys[OSX and 'mq' or 'cq'] = textadept.editing.block_comment -- Do I ever use these? -- newkeys['cf'] = buffer.char_right -- newkeys['cF'] = buffer.char_right_extend -- newkeys['cmf'] = buffer.word_right -- newkeys['cmF'] = buffer.word_right_extend -- newkeys['cb'] = buffer.char_left -- newkeys['cB'] = buffer.char_left_extend -- newkeys['cmb'] = buffer.word_left -- newkeys['cmB'] = buffer.word_left_extend -- newkeys['cn'] = buffer.line_down -- newkeys['cN'] = buffer.line_down_extend -- newkeys['cp'] = buffer.line_up -- newkeys['cP'] = buffer.line_up_extend -- newkeys['ca'] = buffer.vc_home -- newkeys['cA'] = buffer.vc_home_extend -- newkeys['ce'] = buffer.line_end -- newkeys['cE'] = buffer.line_end_extend -- newkeys['aright'] = buffer.word_right -- newkeys['aleft'] = buffer.word_left -- newkeys['cdv'] = buffer.clear -- newkeys['ck'] = function() buffer:line_end_extend() buffer:cut() end -- newkeys['cl'] = buffer.vertical_centre_caret newkeys.fn = OSX and function() return true end or nil newkeys[OSX and 'c@' or 'c '] = complete_symbol end do local function find_in_file() ui.find.in_files = false ui.find.focus() end local function find_in_files() ui.find.in_files = true ui.find.focus() end local function find_next_in_files() ui.find.goto_file_found(false,true) end local function find_previous_in_files() ui.find.goto_file_found(false,false) end newmenu.search = { title = '_Search', SEPARATOR, { '_Find', find_in_file }, { 'Find _Next', ui.find.find_next }, { 'Find _Previous', ui.find.find_prev }, { '_Replace', ui.find.replace }, { 'Replace _All', ui.find.replace_all }, { 'Find _Incremental', ui.find.find_incremental }, SEPARATOR, { 'Find in Fi_les', find_in_files }, { 'Goto Nex_t File Found', find_next_in_files }, { 'Goto Previou_s File Found', find_previous_in_files }, SEPARATOR, { '_Jump to', textadept.editing.goto_line } } -- The few times I use osx I want the same keys ... better explicitly handle -- "not GUI" but I have to test the curses version first anyway. newkeys[OSX and 'mf' or 'cf'] = find_in_file newkeys[OSX and 'mg' or 'cg'] = ui.find.find_next newkeys[OSX and 'mG' or 'cG'] = ui.find.find_prev newkeys[OSX and 'mg' or 'cg'] = textadept.editing.goto_line newkeys['f3'] = not OSX and ui.find.find_next or nil newkeys['sf3'] = not OSX and ui.find.find_prev or nil newkeys[OSX and 'cr' or 'car'] = ui.find.replace newkeys[OSX and 'cR' or 'caR'] = ui.find.replace_all newkeys[OSX and 'cmf' or 'caf'] = ui.find.find_incremental newkeys[OSX and 'mF' or 'cF'] = find_in_files newkeys[OSX and 'cmg' or 'cag'] = find_next_in_files newkeys[OSX and 'cmG' or 'caG'] = find_previous_in_files end do io.quick_open_max = 5000 local function isdir(path) return path and path ~= "" and lfs.attributes(path,'mode') == 'directory' end local function resolveroot(path) local path = runner.resultof("mtxrun --resolve-path TEXMFCONTEXT") if path then return string.match(path,"(.-)%s$") end end local function opencurrentdirectory() local path = buffer.filename if path and path ~= "" then path = string.match(path,"^(.+)[/\\]") if isdir(path) then io.quick_open(path) end end end local function openuserdirectory() local path = resolveroot("TEXMFPROJECT") if isdir(path) then io.quick_open(path .. "/tex/context/user") end end local function openbasedirectory() local path = resolveroot("TEXMFCONTEXT") if isdir(path) then io.quick_open(path .. "/tex/context/base/mkiv") end end local started = false local function startservice() if WIN32 then os.execute([[cmd /c start /min "Context Documentation" mtxrun --script server --auto]]) else os.execute([[mtxrun --script server --start > ~/context-wwwserver.log &]]) end started = true end local function showcommand() -- if not started then -- startservice() -- end local start = buffer.selection_n_start[0] local stop = buffer.selection_n_end[0] if start == stop then buffer:set_target_range(buffer:word_start_position(start,true),buffer:word_end_position(stop,true)) else buffer:set_target_range(start,stop) end local word = buffer.target_text os.execute(format([[mtxrun --gethelp --url="http://localhost:8088/mtx-server-ctx-help.lua?command=%s"]],word or "")) end newmenu.tools = { title = '_Tools', SEPARATOR, { 'Check Source', runner.check }, { 'Process Source', runner.process }, { 'Preview Result', runner.preview }, { 'Show Log File', runner.install("logfile") }, { 'Quit', runner.quit }, SEPARATOR, { 'Open Current Directory', opencurrentdirectory }, { 'Open User Directory', openuserdirectory }, { 'Open Base Directory', openbasedirectory }, SEPARATOR, { 'Purge Files', runner.install("purge") }, { 'Clear Cache', runner.install("clear") }, { 'Generate File Database', runner.install("generate") }, { 'Generate Font Database', runner.install("fonts") }, SEPARATOR, { 'Typeset Listing', runner.install("listing") }, { 'Process and Arrange', runner.install("arrange") }, SEPARATOR, { 'Start Document Service', startservice }, { 'Goto Document Service', showcommand }, SEPARATOR, { 'Show Unicodes', runner.install("unicodes") }, } -- newkeys[OSX and 'mc' or 'cc'] = runner.check newkeys[OSX and 'mr' or 'cr'] = runner.process newkeys[OSX and 'mp' or 'cp'] = runner.preview -- newkeys[OSX and 'mx' or 'cx'] = runner.quit -- makes no sense newkeys['f7'] = runner.process newkeys['f12'] = runner.process end do local function use_tabs() buffer.use_tabs = not buffer.use_tabs events.emit(events.UPDATE_UI) -- for updating statusbar end local function set_eol_mode_crlf() set_eol_mode(buffer.EOL_CRLF) end local function set_eol_mode_lf() set_eol_mode(buffer.EOL_LF) end local function show_eol() buffer.view_eol = not buffer.view_eol end local function wrap_mode() buffer.wrap_mode = buffer.wrap_mode == 0 and buffer.WRAP_WHITESPACE or 0 end function show_white_space() buffer.view_ws = buffer.view_ws == 0 and buffer.WS_VISIBLEALWAYS or 0 end local function update_lexing() buffer:colourise(0,-1) end function set_endoding_utf8() set_encoding('UTF-8') end function set_encoding_ascii() set_encoding('ASCII') end function set_endoding_utf16le() set_encoding('UTF-16LE') end function set_endoding_utf16Be() set_encoding('UTF-16BE') end function goto_prev_buffer() view:goto_buffer(-1) end function goto_next_buffer() view:goto_buffer(1) end newmenu.buffer = { title = '_Buffer', SEPARATOR, { '_Previous Buffer', goto_prev_buffer }, { '_Next Buffer', goto_next_buffer }, { '_Switch to Buffer', ui.switch_buffer }, SEPARATOR, { '_Toggle Use Tabs', use_tabs }, { title = 'EOL Mode', { '_CRLF', set_eol_mode_crlf }, { '_LF', set_eol_mode_lf }, }, { title = 'Encoding', { '_ASCII', set_encoding_ascii }, { '_UTF-8', set_encoding_utf8 }, { 'UTF-16-_BE', set_encoding_utf16le }, { 'UTF-16-_LE', set_encoding_utf16be }, }, SEPARATOR, { 'Toggle View _EOL', show_eol }, { 'Toggle _Wrap Mode', wrap_mode }, { 'Toggle View _Spacing', show_whitespace }, SEPARATOR, { 'Select _Lexer', textadept.file_types.select_lexer }, { 'Refresh _Syntax Highlighting', update_lexing } } newkeys['f5'] = update_lexing newkeys[OSX and 'mp' or 'cs\t'] = goto_prev_buffer newkeys[OSX and 'mn' or 'c\t'] = goto_next_buffer newkeys[OSX and 'mb' or 'cb'] = ui.switch_buffer end do local function toggle_current_fold() buffer:toggle_fold(buffer:line_from_position(buffer.current_pos)) end local function toggle_show_guides() local off = buffer.indentation_guides == 0 buffer.indentation_guides = off and buffer.IV_LOOKBOTH or 0 end local function toggle_virtual_space() local off = buffer.virtual_space_options == 0 buffer.virtual_space_options = off and buffer.VS_USERACCESSIBLE or 0 end local function reset_zoom() buffer.zoom = 0 end newmenu.view = { title = '_View', SEPARATOR, { 'Toggle Current _Fold' , toggle_current_fold }, SEPARATOR, { 'Toggle Show In_dent Guides', toggle_show_guides }, { 'Toggle _Virtual Space', toggle_virtual_space }, SEPARATOR, { 'Zoom _In', buffer.zoom_in }, { 'Zoom _Out', buffer.zoom_out }, { '_Reset Zoom', reset_zoom }, } newkeys[OSX and 'm=' or 'c='] = buffer.zoom_in newkeys[OSX and 'm-' or 'c-'] = buffer.zoom_out newkeys[OSX and 'm0' or 'c0'] = reset_zoom end do -- It's a pitt y that we can't have a proper monospaced font here so we try to make the best of it: local template = "\n\trelease info: %s\t\n\n\tcopyright: %s\t\n\n\tvariant: ConTeXt related editing\t\n\n\tadapted by: Hans Hagen\t" function show_about() ui.dialogs.msgbox { title = "about", informative_text = format(template,(gsub(_RELEASE,"%s+"," ")),(gsub(_COPYRIGHT,"%s+"," "))) } end local function open_url(url) -- adapted from non public open_page local cmd = (WIN32 and 'start ""') or (OSX and 'open') or 'xdg-open' spawn(format('%s "%s"', cmd, url)) end newmenu.help = { title = '_Help', SEPARATOR, { 'ConTeXt garden wiki', function() open_url("http://www.contextgarden.net") end }, -- SEPARATOR, { '_About', show_about } } end do local function replace(oldmenu,newmenu) local n = #newmenu local o = #oldmenu for i=1,n do oldmenu[i] = newmenu[i] end for i=o,n+1,-1 do oldmenu[i] = nil end end replace(textadept.menu.menubar [_L['_File']], newmenu.file) replace(textadept.menu.menubar [_L['_Edit']], newmenu.edit) replace(textadept.menu.menubar [_L['_Search']], newmenu.search) replace(textadept.menu.menubar [_L['_Tools']], newmenu.tools) replace(textadept.menu.menubar [_L['_Buffer']], newmenu.buffer) replace(textadept.menu.menubar [_L['_View']], newmenu.view) replace(textadept.menu.menubar [_L['_Help']], newmenu.help) local char = string.char local combi = { "c", "m", "a", "cm", "ca", "ma", } local pad = { "esc", "del", "bs", "up", "down", "left", "right", "end", "home", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "f10", "f11", "f12", } local s = "s" for i=1,#combi do local c = combi[i] for i=0x20,0x40 do local ci = char(i) keys[ c..ci] = nil keys[s..c..ci] = nil end for i=0x41,0x5A do -- A .. Z local ci = char(i) keys[ c..ci] = nil end for i=0x5B,0x60 do local ci = char(i) keys[ c..ci] = nil keys[s..c..ci] = nil end for i=0x61,0x7A do -- a .. z local ci = char(i) keys[ c..ci] = nil end for i=0x7B,0x7F do local ci = char(i) keys[ c..ci] = nil keys[s..c..ci] = nil end for i=1,#pad do local pi = pad[i] keys[ c..pi] = nil keys[s..c..pi] = nil end end for k, v in next, newkeys do keys[k] = v end end -- We have a different way to set up files and runners. Less distributed and morein the way we -- do things in context. local dummyrunner = function() end local extensions = textadept.file_types.extensions local specifications = runner.specifications local setters = { } local defaults = { check = dummyrunner, process = dummyrunner, preview = dummyrunner, } setmetatable(specifications, { __index = defaults }) function context.install(specification) local suffixes = specification.suffixes if suffixes then local lexer = specification.lexer local setter = specification.setter local encoding = specification.encoding for i=1,#suffixes do local suffix = suffixes[i] if lexer and extensions then extensions[suffix] = lexer end specifications[suffix] = specification if lexer then setters[lexer] = function() if encoding == "7-BIT-ASCII" then setsevenbitascii(buffer) end if setter then setter(lexer) end end end end end end -- Too much interference so I might drop all the old stuff eventually. local function synchronize(lexer) if lexer then local setter = lexer and setters[lexer] if setter then local action = context.synchronize if action then action() end -- userunner() setter(lexer) else -- useoldrunner() end end end events.connect(events.FILE_OPENED,function(filename) synchronize(buffer:get_lexer()) end) events.connect(events.LEXER_LOADED,function(lexer) synchronize(lexer) end) -- obsolete -- events.connect(events.BUFFER_AFTER_SWITCH,function() -- synchronize(buffer:get_lexer()) -- end) -- events.connect(events.VIEW_AFTER_SWITCH,function() -- synchronize(buffer:get_lexer()) -- end) -- events.connect(events.BUFFER_NEW,function() -- synchronize(buffer:get_lexer()) -- end) -- events.connect(events.VIEW_NEW,function() -- synchronize(buffer:get_lexer()) -- end) -- events.connect(events.RESET_AFTER,function() -- synchronize(buffer:get_lexer()) -- end) -- local oldtools = { } -- local usingold = false -- local toolsmenu = textadept.menu.menubar [_L['_Tools']] -- -- for i=1,#toolsmenu do -- oldtools[i] = toolsmenu[i] -- end -- -- local function replace(tools) -- local n = #toolsmenu -- local m = #tools -- for i=1,m do -- toolsmenu[i] = tools[i] -- end -- for i=n,m+1,-1 do -- toolsmenu[i] = nil -- end -- end -- -- local function useoldrunner() -- if not usingold then -- keys [OSX and 'mr' or 'cr' ] = oldrunner.run -- keys [OSX and 'mR' or (GUI and 'cR' or 'cmr')] = oldrunner.compile -- keys [OSX and 'mB' or (GUI and 'cB' or 'cmb')] = oldrunner.build -- keys [OSX and 'mX' or (GUI and 'cX' or 'cmx')] = oldrunner.stop -- -- -- replace(oldtools) -- -- -- usingold = true -- end -- end -- -- local function userunner() -- if usingold then -- keys [OSX and 'mr' or 'cr' ] = runner.process -- keys [OSX and 'mR' or (GUI and 'cR' or 'cmr')] = runner.check -- keys [OSX and 'mB' or (GUI and 'cB' or 'cmb')] = runner.preview -- keys [OSX and 'mX' or (GUI and 'cX' or 'cmx')] = runner.quit -- -- -- replace(newtools) -- -- -- usingold = false -- end -- end -- -- userunner()