diff options
author | Hans Hagen <pragma@wxs.nl> | 2017-04-08 12:28:54 +0200 |
---|---|---|
committer | Context Git Mirror Bot <phg42.2a@gmail.com> | 2017-04-08 12:28:54 +0200 |
commit | ea2466fe69bd082d379e95e1567f3de0b76de243 (patch) | |
tree | 70f1bdcf7d402f2ae013caebf5f4cef5f6c2baed /context/data/textadept/context/modules/textadept-context-runner.lua | |
parent | e32f57c9c5968f0c09130f6e24e28a96d6e1393d (diff) | |
download | context-ea2466fe69bd082d379e95e1567f3de0b76de243.tar.gz |
2017-04-08 12:15:00
Diffstat (limited to 'context/data/textadept/context/modules/textadept-context-runner.lua')
-rw-r--r-- | context/data/textadept/context/modules/textadept-context-runner.lua | 254 |
1 files changed, 254 insertions, 0 deletions
diff --git a/context/data/textadept/context/modules/textadept-context-runner.lua b/context/data/textadept/context/modules/textadept-context-runner.lua new file mode 100644 index 000000000..f06786b00 --- /dev/null +++ b/context/data/textadept/context/modules/textadept-context-runner.lua @@ -0,0 +1,254 @@ +local info = { + version = 1.002, + comment = "prototype textadept runner for context/metafun", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files", +} + +-- This is an adapted version of the run code by mitchell.att.foicica.corunner. The main +-- reason I started patching is that long lines got broken in the middle so we needed +-- to have a more clever line splitter that saves half of a line for later. Then I +-- decided to come up with a few more variants so in the end ... it's just too tempting +-- make something that exactly suits out needs. In fact, maybe I'll do that some day: +-- take core textadept and make a dedicated variant for the kind of processing that we +-- do and make it suitable for document authors (the manual says that is doable). In that +-- case I can also use a lot of already written helpers. +-- +-- The error scanner is not needed. If I need one, it will be using a lexers applied +-- afterwards because working on half lines is not going to work out well anyway. +-- +-- Here I removed iconv calls as in context we use utf (less hassle with fonts too). One +-- can always use the original approach. +-- +-- The events seems to have hard coded names, Also, the name of the message buffer cannot +-- be changes because otherwise we get a message when the session is restored. I don't +-- care about locales. +-- +-- Somehow th eprocess hangs when I refresh the pdf viewer, this doesn't happen in scite so +-- the underlying code is for the moment less reliant. + +local match, gsub, find, format = string.match, string.gsub, string.find, string.format +local assert, type = assert, type + +local original = textadept.run +local runner = { } + +runner.MARK_WARNING = original.MARK_WARNING +runner.MARK_ERROR = original.MARK_ERROR + +local specifications = { } +runner.specifications = specifications + +events.CHECK_OUTPUT = 'build_output' -- 'check_output' +events.PROCESS_OUTPUT = 'run_output' -- 'process_output' +events.PREVIEW_OUTPUT = 'compile_output' -- 'preview_output' + +local eventtags = { + check = events.CHECK_OUTPUT, + process = events.PROCESS_OUTPUT, + preview = events.PREVIEW_OUTPUT, +} + +local OUTPUT_BUFFER = '[Message Buffer]' -- CONSOLE + +local currentprocess = nil +local xbuffer = nil + +local function find_buffer(buffer_type) + for i=1,#_BUFFERS do + local buffer = _BUFFERS[i] + if buffer._type == buffer_type then + return buffer + end + end +end + +local function print_output(str) + local print_buffer = find_buffer(OUTPUT_BUFFER) + if not print_buffer then + if not ui.tabs then + view:split() + end + print_buffer = buffer.new() + print_buffer._type = OUTPUT_BUFFER + events.emit(events.FILE_OPENED) + else + for i=1,#_VIEWS do + local view = _VIEWS[i] + if view.buffer._type == OUTPUT_BUFFER then + ui.goto_view(view) + break + end + end + if view.buffer._type ~= OUTPUT_BUFFER then + view:goto_buffer(print_buffer) + end + end + print_buffer:append_text(str) + print_buffer:goto_pos(buffer.length) + print_buffer:set_save_point() + return true -- quits +end + +local function clear_output() + xbuffer = buffer + local print_buffer = find_buffer(OUTPUT_BUFFER) + if print_buffer then + print_buffer:clear_all() + end +end + +local function is_output(buffer) + return buffer._type == OUTPUT_BUFFER +end + +local function process(buffer,filename,action) + local event = eventtags[action] + if not event then + return + end + if not filename then + filename = buffer.filename + end + if filename == buffer.filename then + buffer:annotation_clear_all() -- needed ? + io.save_file() + end + local suffix = match(filename,'[^/\\.]+$') + local specification = specifications[suffix] + if not specification then + return + end + local command = specification[action] + if type(command) == "string" then + -- we're ok, some day also more specific table support, e.g. when we want + -- to hook in a log lexer + else + return + end + clear_output() + local pathpart = '' + local basename = filename + if find(filename,'[/\\]') then + pathpart, basename = match(filename,'^(.+[/\\])([^/\\]+)$') + end + -- beter strip one from the end + local nameonly = match(basename,'^(.+)%.') + -- more in sync which what we normally do + command = gsub(command,'%%(.-)%%', { + filename = filename, + pathname = dirname, + dirname = dirname, + pathpart = dirname, + basename = basename, + nameonly = nameonly, + suffix = suffix, + }) + -- for fun i'll add a ansi escape sequence lexer some day + local function emit_output(output) + events.emit(event,output) + end + local function exit_output(status) + events.emit(event,format("\n\n> exit: %s, press esc to return to source\n",status)) + end + events.emit(event,format("> command: %s\n",command)) + currentprocess = assert(spawn(command, pathpart, emit_output, emit_output, exit_output)) +end + +function runner.check(filename) + process(buffer,filename,"check") +end + +function runner.process(filename) + process(buffer,filename,"process") +end + +function runner.preview(filename) + process(buffer,filename,"preview") +end + +function runner.quit() + if currentprocess then + assert(currentprocess:kill()) + end +end + +local function char_added(code) + if code == 10 and currentprocess and currentprocess:status() == 'running' and buffer._type == OUTPUT_BUFFER then + local line_num = buffer:line_from_position(buffer.current_pos) - 1 + currentprocess:write((buffer:get_line(line_num))) + end + return true -- quits +end + +function runner.goto_error(line, next) + -- see original code for how to do it +end + +local function key_press(code) + if xbuffer and keys.KEYSYMS[code] == 'esc' then + view:goto_buffer(xbuffer) + return true + end +end + +local function double_click() + if xbuffer and is_output(buffer) then + view:goto_buffer(xbuffer) + return true + end +end + +-- Tricky: we can't reset an event (because we need to know the function which is +-- local. So, a first solution injected a false into the table which will trigger +-- a break and then I found out that returning true has the same effect. + +events.connect(events.COMPILE_OUTPUT, print_output, 1) +events.connect(events.RUN_OUTPUT, print_output, 1) +events.connect(events.BUILD_OUTPUT, print_output, 1) +events.connect(events.CHAR_ADDED, char_added, 1) +events.connect(events.KEYPRESS, key_press, 1) +events.connect(events.DOUBLE_CLICK, double_click, 1) + +return runner + +-- The ui.print function is a bit heavy as each flush will parse the whole list of buffers. +-- Also it does some tab magic that we don't need or want. There is the original ui.print for +-- that. FWIW, speed is not an issue. Some optimizations: + +-- function _print(buffer_type,one,two,...) +-- ... +-- print_buffer:append_text(one) +-- if two then +-- print_buffer:append_text(two) +-- for i=1, select('#', ...) do +-- print_buffer:append_text((select(i,...))) +-- end +-- end +-- print_buffer:append_text('\n') +-- ... +-- end +-- +-- And a better splitter: +-- ... +-- local rest +-- local function emit_output(output) +-- for line, lineend in output:gmatch('([^\r\n]+)([\r\n]?)') do +-- if rest then +-- line = rest .. line +-- rest = nil +-- end +-- if lineend and lineend ~= "" then +-- events.emit(event, line, ext_or_lexer) +-- else +-- rest = line +-- end +-- end +-- end +-- ... +-- if rest then +-- events.emit(event,rest,ext_or_lexer) +-- end +-- events.emit(event, '> exit status: '..status) +-- ... |