summaryrefslogtreecommitdiff
path: root/context/data/textadept/context/modules/textadept-context-runner.lua
diff options
context:
space:
mode:
authorHans Hagen <pragma@wxs.nl>2017-04-08 12:28:54 +0200
committerContext Git Mirror Bot <phg42.2a@gmail.com>2017-04-08 12:28:54 +0200
commitea2466fe69bd082d379e95e1567f3de0b76de243 (patch)
tree70f1bdcf7d402f2ae013caebf5f4cef5f6c2baed /context/data/textadept/context/modules/textadept-context-runner.lua
parente32f57c9c5968f0c09130f6e24e28a96d6e1393d (diff)
downloadcontext-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.lua254
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)
+-- ...