aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar mitchell <70453897+667e-11@users.noreply.github.com>2016-06-15 08:53:43 -0400
committerGravatar mitchell <70453897+667e-11@users.noreply.github.com>2016-06-15 08:53:43 -0400
commitcc23cab69c4ebf172df670920beb01824c0cbe0b (patch)
tree69824e46593f33079b867c0e867db7cb5c2f56e2
parenta09f1751c01d66a3b7519c72909746611d12a7f2 (diff)
Refactored `textadept.run`; modules/textadept/run.lua
Renamed settings, allowed filename arguments to `run()` and `compile()`, changed parameters to `*_OUTPUT` events, changed format of `error_patterns`, and removed syntax checking.
-rw-r--r--doc/manual.md24
-rw-r--r--modules/textadept/run.lua432
2 files changed, 228 insertions, 228 deletions
diff --git a/doc/manual.md b/doc/manual.md
index 4794a8fd..5910c7e0 100644
--- a/doc/manual.md
+++ b/doc/manual.md
@@ -1859,6 +1859,10 @@ terminal's constraints:
Old API |Change |New API
----------------------------------|:------:|-------
+**events** | |
+COMPILE\_OUTPUT lexer, output |Changed |[COMPILE\_OUTPUT][] output, ext/lex
+RUN\_OUTPUT lexer, output |Changed |[RUN\_OUTPUT][] output, ext/lexer
+BUILD\_OUTPUT project, output |Changed |[BUILD\_OUTPUT][] output
**io** | |
snapopen(...) |Changed |[quick\_open][](paths, filter, opts)
snapopen\_filters |Renamed |[quick\_open\_filters][]
@@ -1879,11 +1883,26 @@ STRIP\_TRAILING\_SPACES |Replaced|[strip\_trailing\_spaces][]
AUTOCOMPLETE\_ALL |Replaced|[autocomplete\_all\_words][]
char\_matches |Replaced|[auto\_pairs][]
braces |Replaced|[brace\_matches][]
+**textadept.run** | |
+RUN\_IN\_BACKGROUND |Renamed |[run\_in\_background][]
+CHECK\_SYNTAX |Removed |
+GOTO\_SYNTAX\_ERRORS |Removed |
+cwd |Removed |
+proc |Removed |
+compile() |Changed |[compile][](filename)
+run() |Changed |[run][](filename)
+build() |Changed |[build][](root\_directory)
+[error\_patterns][] |Changed |_(changed format)_
+syntax\_commands |Removed |
+syntax\_error\_patterns |Removed |
**textadept.session** | |
DEFAULT\_SESSION |Renamed |[default\_session][]
SAVE\_ON\_QUIT |Renamed |[save\_on\_quit][]
MAX\_RECENT\_FILES |Renamed |[max\_recent\_files][]
+[COMPILE\_OUTPUT]: api.html#events.COMPILE_OUTPUT
+[RUN\_OUTPUT]: api.html#events.RUN_OUTPUT
+[BUILD\_OUTPUT]: api.html#events.BUILD_OUTPUT
[default\_filter]: api.html#lfs.default_filter
[dir\_foreach()]: api.html#lfs.dir_foreach
[silent\_print]: api.html#ui.silent_print
@@ -1898,6 +1917,11 @@ MAX\_RECENT\_FILES |Renamed |[max\_recent\_files][]
[strip\_trailing\_spaces]: api.html#textadept.editing.strip_trailing_spaces
[autocomplete\_all\_words]: api.html#textadept.editing.autocomplete_all_words
[brace\_matches]: api.html#textadept.editing.brace_matches
+[run\_in\_background]: api.html#textadept.run.run_in_background
+[compile]: api.html#textadept.run.compile
+[run]: api.html#textadept.run.run
+[build]: api.html#textadept.run.build
+[error\_patterns]: api.html#textadept.run.error_patterns
[default\_session]: api.html#textadept.session.default_session
[save\_on\_quit]: api.html#textadept.session.save_on_quit
[max\_recent\_files]: api.html#textadept.session.max_recent_files
diff --git a/modules/textadept/run.lua b/modules/textadept/run.lua
index fa49d746..7aa9c61a 100644
--- a/modules/textadept/run.lua
+++ b/modules/textadept/run.lua
@@ -4,65 +4,47 @@ local M = {}
--[[ This comment is for LuaDoc.
---
--- Compile, run, and check the syntax of source code files with Textadept.
+-- Compile and run source code files with Textadept.
-- [Language modules](#_M.Compile.and.Run) may tweak the `compile_commands`,
--- `run_commands`, `error_patterns`, `syntax_commands`, and
--- `syntax_error_patterns` tables for particular languages.
+-- `run_commands`, and `error_patterns` tables for particular languages.
-- The user may tweak `build_commands` for particular projects.
--- @field RUN_IN_BACKGROUND (bool)
+-- @field run_in_background (bool)
-- Run shell commands silently in the background.
-- This only applies when the message buffer is open, though it does not have
-- to be visible.
-- The default value is `false`.
--- @field CHECK_SYNTAX (bool)
--- Check the syntax of sources files upon saving them.
--- This applies only to languages that have syntax-checking commands and error
--- message patterns defined in the `syntax_commands` and
--- `syntax_error_patterns` tables, respectively.
--- The default value is `false`.
--- @field GOTO_SYNTAX_ERRORS (bool)
--- Immediately jump to recognized syntax errors after saving a source file.
--- The default value is `true`.
-- @field MARK_WARNING (number)
-- The run or compile warning marker number.
-- @field MARK_ERROR (number)
-- The run or compile error marker number.
--- @field cwd (string, Read-only)
--- The most recently executed compile or run shell command's working
--- directory.
--- It is used for going to error messages with relative file paths.
--- @field proc (process)
--- The currently running process or the most recent process run.
-- @field _G.events.COMPILE_OUTPUT (string)
-- Emitted when executing a language's compile shell command.
-- By default, compiler output is printed to the message buffer. To override
-- this behavior, connect to the event with an index of `1` and return `true`.
-- Arguments:
--
--- * `lexer`: The language's lexer name.
-- * `output`: A line of string output from the command.
+-- * `ext_or_lexer`: The file extension or lexer name associated with the
+-- executed compile command.
-- @field _G.events.RUN_OUTPUT (string)
-- Emitted when executing a language's run shell command.
-- By default, output is printed to the message buffer. To override this
-- behavior, connect to the event with an index of `1` and return `true`.
-- Arguments:
--
--- * `lexer`: The language's lexer name.
-- * `output`: A line of string output from the command.
+-- * `ext_or_lexer`: The file extension or lexer name associated with the
+-- executed run command.
-- @field _G.events.BUILD_OUTPUT (string)
-- Emitted when executing a project's build shell command.
-- By default, output is printed to the message buffer. To override this
-- behavior, connect to the event with an index of `1` and return `true`.
-- Arguments:
--
--- * `project`: The path to the project being built or the current working
--- directory of the project being built.
-- * `output`: A line of string output from the command.
module('textadept.run')]]
-M.RUN_IN_BACKGROUND = false
-M.CHECK_SYNTAX = false
-M.GOTO_SYNTAX_ERRORS = true
+M.run_in_background = false
M.MARK_WARNING = _SCINTILLA.next_marker_number()
M.MARK_ERROR = _SCINTILLA.next_marker_number()
@@ -71,119 +53,122 @@ M.MARK_ERROR = _SCINTILLA.next_marker_number()
events.COMPILE_OUTPUT, events.RUN_OUTPUT = 'compile_output', 'run_output'
events.BUILD_OUTPUT = 'build_output'
--- When running commands, note the current view since output is shown in a split
--- view. Jumping to any warnings or errors should be done in the original view.
-local preferred_view
-
--- Executes a compile, run, or build shell command from *commands*.
--- Emits events named *event*.
--- @param commands Either `compile_commands`, `run_commands`, or
--- `build_commands`.
--- @param event Event to emit upon command output.
--- @see _G.events
-local function run_command(commands, event)
- local command, data
- if commands ~= M.build_commands then
- if not buffer.filename then return end
- buffer:annotation_clear_all()
- io.save_file()
- command = commands[buffer.filename] or
- commands[buffer.filename:match('[^.]+$')] or
- commands[buffer:get_lexer()]
- M.cwd = buffer.filename:match('^(.+)[/\\][^/\\]+$') or ''
- data = buffer:get_lexer()
- else
- for i = 1, #_BUFFERS do _BUFFERS[i]:annotation_clear_all() end
- M.cwd = io.get_project_root()
- if not M.cwd then return end
- command = commands[M.cwd]
- if not command then
- local lfs_attributes = lfs.attributes
- for build_file, build_command in pairs(commands) do
- if lfs_attributes(M.cwd..'/'..build_file) then
- local button, utf8_cmd = ui.dialogs.inputbox{
- title = _L['Command'], informative_text = M.cwd,
- text = build_command, button1 = _L['_OK'], button2 = _L['_Cancel']
- }
- if button == 1 then command = utf8_cmd:iconv(_CHARSET, 'UTF-8') end
- break
- end
- end
- end
- data = M.cwd
- end
- if type(command) == 'function' then
- local wd
- command, wd = command()
- if wd then M.cwd, data = wd, commands ~= M.build_commands and data or wd end
- end
- if not command then return end
- if buffer.filename then
- local filepath, filedir, filename = buffer.filename, '', buffer.filename
- if filepath:find('[/\\]') then
- filedir, filename = filepath:match('^(.+[/\\])([^/\\]+)$')
- end
- local filename_noext = filename:match('^(.+)%.')
- command = command:gsub('%%([pdfe])', {
- p = filepath, d = filedir, f = filename, e = filename_noext
- })
- end
+-- Keep track of: the last process spawned in order to kill it if requested; the
+-- cwd of that process in order to jump to relative file paths in recognized
+-- warning or error messages; and the view the process was spawned from in order
+-- to jump to messages (which are displayed in a split view) in the original
+-- view.
+local proc, cwd, preferred_view
- preferred_view = view
- local function emit_output(output, focus)
- ui.silent_print = not focus
- for line in output:gmatch('[^\r\n]+') do events.emit(event, data, line) end
- ui.silent_print = false
- end
- local function emit_status(status) emit_output('> exit status: '..status) end
-
- if commands == M.build_commands or
- M.cwd ~= (buffer.filename:match('^(.+)[/\\][^/\\]+$') or '') then
- emit_output('> cd '..M.cwd)
- end
- emit_output('> '..command:iconv('UTF-8', _CHARSET), not M.RUN_IN_BACKGROUND)
- M.proc = assert(spawn(command, M.cwd, emit_output, emit_output, emit_status))
-end
-
--- Parses the given message for a warning or error message and returns a table
--- of the warning/error's details.
+-- Scans the given message for a warning or error message and, if one is found,
+-- returns table of the warning/error's details.
-- @param message The message to parse for warnings or errors. The message
-- is assumed to be encoded in _CHARSET.
+-- @param ext_or_lexer Optional file extension or lexer name associated with the
+-- shell command that produced the warning/error.
+-- @return error details table with 'filename', 'line', 'column', and 'message'
+-- fields along with a 'warning' flag.
-- @see error_patterns
-local function get_error(message)
- for i = 1, #M.error_patterns do
- local patt = M.error_patterns[i]
- if message:find(patt) then
- local captures = {message:match(patt)}
- for detail in patt:gmatch('[^%%](%b())') do
- if detail == '(.-)' then
- captures.filename = table.remove(captures, 1)
- elseif detail == '(%d+)' then
- captures.line = tonumber(table.remove(captures, 1))
+local function scan_for_error(message, ext_or_lexer)
+ for key, patterns in pairs(M.error_patterns) do
+ if ext_or_lexer and key ~= ext_or_lexer then goto continue end
+ for i = 1, #patterns do
+ if not message:find(patterns[i]) then goto continue end
+ -- Extract details from the warning or error.
+ local details, j = {message:match(patterns[i])}, 1
+ for capture in patterns[i]:gmatch('[^%%](%b())') do
+ if capture == '(.-)' then
+ details.filename = details[j]
+ elseif capture == '(%d+)' then
+ local line_or_column = not details.line and 'line' or 'column'
+ details[line_or_column] = tonumber(details[j])
else
- captures.message = table.remove(captures, 1)
+ details.message = details[j]
end
+ j = j + 1
end
- local warn = message:find('[Ww]arning') and not message:find('[Ee]rror')
- captures.text, captures.warning = message, warn
- return captures
+ details.warning = message:lower():find('warning') and
+ not message:lower():find('error')
+ -- Compile and run commands specify the file extension or lexer used to
+ -- determine the command, so the error patterns used are guaranteed to be
+ -- correct. Build commands have no such context and instead iterate
+ -- through all possible error patterns. Only consider the error/warning
+ -- valid if the extracted filename's extension or lexer matches the error
+ -- pattern's extension or lexer.
+ if ext_or_lexer then return details end
+ local ext = details.filename:match('[^/\\.]+$')
+ local lexer = textadept.file_types.extensions[ext]
+ if ext == key or lexer == key then return details end
+ ::continue::
end
+ ::continue::
end
return nil
end
--- Prints the output from a run or compile shell command.
+-- Prints the output from a compile, run, or build shell command.
-- Assume output is UTF-8 unless there's a recognized warning or error message.
-- In that case assume it is encoded in _CHARSET and mark it.
--- @param _ The current lexer.
+-- All stdout and stderr from the command is printed silently.
-- @param output The output to print.
-local function print_output(_, output)
- local error = get_error(output)
+-- @param ext_or_lexer Optional file extension or lexer name associated with the
+-- executed command. This is used for better error detection in compile and
+-- run commands.
+local function print_output(output, ext_or_lexer)
+ local error = scan_for_error(output, ext_or_lexer)
+ ui.silent_print = (M.run_in_background or ext_or_lexer or
+ not output:find('^> ') or output:find('^> exit')) and true
ui.print(not error and output or output:iconv('UTF-8', _CHARSET))
- if not error then return end
- -- Current position is one line below the error due to ui.print()'s '\n'.
- buffer:marker_add(buffer.line_count - 2,
- error.warning and M.MARK_WARNING or M.MARK_ERROR)
+ ui.silent_print = false
+ if error then
+ -- Current position is one line below the error due to ui.print()'s '\n'.
+ buffer:marker_add(buffer.line_count - 2,
+ error.warning and M.MARK_WARNING or M.MARK_ERROR)
+ end
+end
+
+-- Compiles or runs file *filename* based on a shell command in *commands*.
+-- @param filename The file to run.
+-- @param commands Either `compile_commands` or `run_commands`.
+local function compile_or_run(filename, commands)
+ if filename == buffer.filename then
+ buffer:annotation_clear_all()
+ io.save_file()
+ end
+ -- Determine the command.
+ local ext = filename:match('[^/\\.]+$')
+ local lexer = filename == buffer.filename and buffer:get_lexer() or
+ textadept.file_types.extensions[ext]
+ local command = commands[filename] or commands[ext] or commands[lexer]
+ local working_dir
+ if type(command) == 'function' then command, working_dir = command() end
+ if not command then return end
+ -- Replace macros in the command.
+ local dirname, basename = '', filename
+ if filename:find('[/\\]') then
+ dirname, basename = filename:match('^(.+[/\\])([^/\\]+)$')
+ end
+ local basename_no_ext = basename:match('^(.+)%.')
+ command = command:gsub('%%([pdfe])', {
+ p = filename, d = dirname, f = basename, e = basename_no_ext
+ })
+ -- Prepare to run the command.
+ preferred_view = view
+ local event = commands == M.compile_commands and events.COMPILE_OUTPUT or
+ events.RUN_OUTPUT
+ local ext_or_lexer = commands[ext] and ext or lexer
+ local function emit_output(output)
+ for line in output:gmatch('[^\r\n]+') do
+ events.emit(event, line, ext_or_lexer)
+ end
+ end
+ -- Run the command.
+ cwd = working_dir or dirname
+ if cwd ~= dirname then events.emit(event, '> cd '..cwd) end
+ events.emit(event, '> '..command:iconv('UTF-8', _CHARSET))
+ proc = assert(spawn(command, cwd, emit_output, emit_output, function(status)
+ events.emit(event, '> exit status: '..status)
+ end))
end
---
@@ -200,16 +185,23 @@ end
-- is the current file's parent directory.
-- @class table
-- @name compile_commands
-M.compile_commands = {actionscript='mxmlc "%f"',ada='gnatmake "%f"',ansi_c='gcc -o "%e" "%f"',antlr='antlr4 "%f"',g='antlr3 "%f"',applescript='osacompile "%f" -o "%e.scpt"',asm='nasm "%f" && ld "%e.o" -o "%e"',boo='booc "%f"',caml='ocamlc -o "%e" "%f"',csharp=WIN32 and 'csc "%f"' or 'mcs "%f"',cpp='g++ -o "%e" "%f"',coffeescript='coffee -c "%f"',context='context --nonstopmode "%f"',cuda=WIN32 and 'nvcc -o "%e.exe" "%f"' or 'nvcc -o "%e" "%f"',dmd='dmd "%f"',dot='dot -Tps "%f" -o "%e.ps"',eiffel='se c "%f"',elixir='elixirc "%f"',erlang='erl -compile "%e"',fsharp=WIN32 and 'fsc.exe "%f"' or 'mono fsc.exe "%f"',fortran='gfortran -o "%e" "%f"',gap='gac -o "%e" "%f"',go='go build "%f"',groovy='groovyc "%f"',haskell=WIN32 and 'ghc -o "%e.exe" "%f"' or 'ghc -o "%e" "%f"',inform=function() return 'inform -c "'..buffer.filename:match('^(.+%.inform[/\\])Source')..'"' end,java='javac "%f"',ltx='pdflatex -file-line-error -halt-on-error "%f"',less='lessc "%f" "%e.css"',lilypond='lilypond "%f"',lisp='clisp -c "%f"',litcoffee='coffee -c "%f"',lua='luac -o "%e.luac" "%f"',moon='moonc "%f"',markdown='markdown "%f" > "%e.html"',nemerle='ncc "%f" -out:"%e.exe"',nim='nim c "%f"',nsis='MakeNSIS "%f"',objective_c='gcc -o "%e" "%f"',pascal='fpc "%f"',perl='perl -c "%f"',php='php -l "%f"',prolog='gplc --no-top-level "%f"',python='python -m py_compile "%f"',ruby='ruby -c "%f"',rust='rustc "%f"',sass='sass "%f" "%e.css"',scala='scalac "%f"',tex='pdflatex -file-line-error -halt-on-error "%f"',vala='valac "%f"',vb=WIN32 and 'vbc "%f"' or 'vbnc "%f"',}
+M.compile_commands = {actionscript='mxmlc "%f"',ada='gnatmake "%f"',ansi_c='gcc -o "%e" "%f"',antlr='antlr4 "%f"',g='antlr3 "%f"',applescript='osacompile "%f" -o "%e.scpt"',asm='nasm "%f"'--[[ && ld "%e.o" -o "%e"']],boo='booc "%f"',caml='ocamlc -o "%e" "%f"',csharp=WIN32 and 'csc "%f"' or 'mcs "%f"',coffeescript='coffee -c "%f"',context='context --nonstopmode "%f"',cpp='g++ -o "%e" "%f"',cuda=WIN32 and 'nvcc -o "%e.exe" "%f"' or 'nvcc -o "%e" "%f"',dmd='dmd "%f"',dot='dot -Tps "%f" -o "%e.ps"',eiffel='se c "%f"',elixir='elixirc "%f"',erlang='erl -compile "%e"',faust='faust -o "%e.cpp" "%f"',fsharp=WIN32 and 'fsc.exe "%f"' or 'mono fsc.exe "%f"',fortran='gfortran -o "%e" "%f"',gap='gac -o "%e" "%f"',go='go build "%f"',groovy='groovyc "%f"',haskell=WIN32 and 'ghc -o "%e.exe" "%f"' or 'ghc -o "%e" "%f"',inform=function() return 'inform -c "'..buffer.filename:match('^(.+%.inform[/\\])Source')..'"' end,java='javac "%f"',ltx='pdflatex -file-line-error -halt-on-error "%f"',less='lessc --no-color "%f" "%e.css"',lilypond='lilypond "%f"',lisp='clisp -c "%f"',litcoffee='coffee -c "%f"',lua='luac -o "%e.luac" "%f"',moon='moonc "%f"',markdown='markdown "%f" > "%e.html"',nemerle='ncc "%f" -out:"%e.exe"',nim='nim c "%f"',nsis='MakeNSIS "%f"',objective_c='gcc -o "%e" "%f"',pascal='fpc "%f"',perl='perl -c "%f"',php='php -l "%f"',prolog='gplc --no-top-level "%f"',python='python -m py_compile "%f"',ruby='ruby -c "%f"',rust='rustc "%f"',sass='sass "%f" "%e.css"',scala='scalac "%f"',tex='pdflatex -file-line-error -halt-on-error "%f"',vala='valac "%f"',vb=WIN32 and 'vbc "%f"' or 'vbnc "%f"',}
---
--- Compiles the current file based on its filename, extension, or language using
--- the shell command from the `compile_commands` table.
+-- Compiles file *filename* or the current file using an appropriate shell
+-- command from the `compile_commands` table.
+-- The shell command is determined from the file's filename, extension, or
+-- language in that order.
-- Emits `COMPILE_OUTPUT` events.
+-- @param filename Optional path to the file to compile. The default value is
+-- the current file's filename.
-- @see compile_commands
-- @see _G.events
-- @name compile
-function M.compile() run_command(M.compile_commands, events.COMPILE_OUTPUT) end
+function M.compile(filename)
+ if not filename and not buffer.filename then return end
+ compile_or_run(filename or buffer.filename, M.compile_commands)
+end
events.connect(events.COMPILE_OUTPUT, print_output)
---
@@ -226,16 +218,23 @@ events.connect(events.COMPILE_OUTPUT, print_output)
-- is the current file's parent directory.
-- @class table
-- @name run_commands
-M.run_commands = {actionscript=WIN32 and 'start "" "%e.swf"' or OSX and 'open "file://%e.swf"' or 'xdg-open "%e.swf"',ada=WIN32 and '"%e"' or './"%e"',ansi_c=WIN32 and '"%e"' or './"%e"',applescript='osascript "%f"',asm='./"%e"',awk='awk -f "%f"',batch='"%f"',boo='booi "%f"',caml='ocamlrun "%e"',csharp=WIN32 and '"%e"' or 'mono "%e.exe"',cpp=WIN32 and '"%e"' or './"%e"',chuck='chuck "%f"',cmake='cmake -P "%f"',coffeescript='coffee "%f"',context=WIN32 and 'start "" "%e.pdf"' or OSX and 'open "%e.pdf"' or 'xdg-open "%e.pdf"',cuda=WIN32 and '"%e"' or './"%e"',dmd=WIN32 and '"%e"' or './"%e"',eiffel="./a.out",elixir='elixir "%f"',fsharp=WIN32 and '"%e"' or 'mono "%e.exe"',forth='gforth "%f" -e bye',fortran=WIN32 and '"%e"' or './"%e"',gnuplot='gnuplot "%f"',go='go run "%f"',groovy='groovy "%f"',haskell=WIN32 and '"%e"' or './"%e"',html=WIN32 and 'start "" "%f"' or OSX and 'open "file://%f"' or 'xdg-open "%f"',icon='icont "%e" -x',idl='idl -batch "%f"',Io='io "%f"',java='java "%e"',javascript='node "%f"',ltx=WIN32 and 'start "" "%e.pdf"' or OSX and 'open "%e.pdf"' or 'xdg-open "%e.pdf"',less='lessc --no-color "%f"',lilypond=WIN32 and 'start "" "%e.pdf"' or OSX and 'open "%e.pdf"' or 'xdg-open "%e.pdf"',lisp='clisp "%f"',litcoffee='coffee "%f"',lua='lua -e "io.stdout:setvbuf(\'no\')" "%f"',makefile=WIN32 and 'nmake -f "%f"' or 'make -f "%f"',markdown='markdown "%f"',moon='moon "%f"',nemerle=WIN32 and '"%e"' or 'mono "%e.exe"',nim='nim c -r "%f"',objective_c=WIN32 and '"%e"' or './"%e"',pascal=WIN32 and '"%e"' or './"%e"',perl='perl "%f"',php='php "%f"',pike='pike "%f"',pkgbuild='makepkg -p "%f"',prolog=WIN32 and '"%e"' or './"%e"',pure='pure "%f"',python='python -u "%f"',rstats=WIN32 and 'Rterm -f "%f"' or 'R -f "%f"',rebol='REBOL "%f"',rexx=WIN32 and 'rexx "%e"' or 'regina "%e"',ruby='ruby "%f"',rust=WIN32 and '"%e"' or './"%e"',sass='sass "%f"',scala='scala "%e"',bash='bash "%f"',csh='tcsh "%f"',sh='sh "%f"',zsh='zsh "%f"',smalltalk='gst "%f"',snobol4='snobol4 -b "%f"',tcl='tclsh "%f"',tex=WIN32 and 'start "" "%e.pdf"' or OSX and 'open "%e.pdf"' or 'xdg-open "%e.pdf"',vala=WIN32 and '"%e"' or './"%e"',vb=WIN32 and '"%e"' or 'mono "%e.exe"',}
+M.run_commands = {actionscript=WIN32 and 'start "" "%e.swf"' or OSX and 'open "file://%e.swf"' or 'xdg-open "%e.swf"',ada=WIN32 and '"%e"' or './"%e"',ansi_c=WIN32 and '"%e"' or './"%e"',applescript='osascript "%f"',asm='./"%e"',awk='awk -f "%f"',batch='"%f"',boo='booi "%f"',caml='ocamlrun "%e"',csharp=WIN32 and '"%e"' or 'mono "%e.exe"',chuck='chuck "%f"',cmake='cmake -P "%f"',coffeescript='coffee "%f"',context=WIN32 and 'start "" "%e.pdf"' or OSX and 'open "%e.pdf"' or 'xdg-open "%e.pdf"',cpp=WIN32 and '"%e"' or './"%e"',cuda=WIN32 and '"%e"' or './"%e"',dart='dart "%f"',dmd=WIN32 and '"%e"' or './"%e"',eiffel="./a.out",elixir='elixir "%f"',fsharp=WIN32 and '"%e"' or 'mono "%e.exe"',forth='gforth "%f" -e bye',fortran=WIN32 and '"%e"' or './"%e"',gnuplot='gnuplot "%f"',go='go run "%f"',groovy='groovy "%f"',haskell=WIN32 and '"%e"' or './"%e"',html=WIN32 and 'start "" "%f"' or OSX and 'open "file://%f"' or 'xdg-open "%f"',icon='icont "%e" -x',idl='idl -batch "%f"',Io='io "%f"',java='java "%e"',javascript='node "%f"',ltx=WIN32 and 'start "" "%e.pdf"' or OSX and 'open "%e.pdf"' or 'xdg-open "%e.pdf"',less='lessc --no-color "%f"',lilypond=WIN32 and 'start "" "%e.pdf"' or OSX and 'open "%e.pdf"' or 'xdg-open "%e.pdf"',lisp='clisp "%f"',litcoffee='coffee "%f"',lua='lua -e "io.stdout:setvbuf(\'no\')" "%f"',makefile=WIN32 and 'nmake -f "%f"' or 'make -f "%f"',markdown='markdown "%f"',moon='moon "%f"',nemerle=WIN32 and '"%e"' or 'mono "%e.exe"',nim='nim c -r "%f"',objective_c=WIN32 and '"%e"' or './"%e"',pascal=WIN32 and '"%e"' or './"%e"',perl='perl "%f"',php='php "%f"',pike='pike "%f"',pkgbuild='makepkg -p "%f"',prolog=WIN32 and '"%e"' or './"%e"',pure='pure "%f"',python='python -u "%f"',rstats=WIN32 and 'Rterm -f "%f"' or 'R -f "%f"',rebol='REBOL "%f"',rexx=WIN32 and 'rexx "%f"' or 'regina "%f"',ruby='ruby "%f"',rust=WIN32 and '"%e"' or './"%e"',sass='sass "%f"',scala='scala "%e"',bash='bash "%f"',csh='tcsh "%f"',sh='sh "%f"',zsh='zsh "%f"',smalltalk='gst "%f"',snobol4='snobol4 -b "%f"',tcl='tclsh "%f"',tex=WIN32 and 'start "" "%e.pdf"' or OSX and 'open "%e.pdf"' or 'xdg-open "%e.pdf"',vala=WIN32 and '"%e"' or './"%e"',vb=WIN32 and '"%e"' or 'mono "%e.exe"',}
---
--- Runs the current file based on its filename, extension, or language using the
--- shell command from the `run_commands` table.
+-- Runs file *filename* or the current file using an appropriate shell command
+-- from the `run_commands` table.
+-- The shell command is determined from the file's filename, extension, or
+-- language in that order.
-- Emits `RUN_OUTPUT` events.
+-- @param filename Optional path to the file to run. The default value is the
+-- current file's filename.
-- @see run_commands
-- @see _G.events
-- @name run
-function M.run() run_command(M.run_commands, events.RUN_OUTPUT) end
+function M.run(filename)
+ if not filename and not buffer.filename then return end
+ compile_or_run(filename or buffer.filename, M.run_commands)
+end
events.connect(events.RUN_OUTPUT, print_output)
---
@@ -248,26 +247,64 @@ events.connect(events.RUN_OUTPUT, print_output)
M.build_commands = {--[[Ant]]['build.xml']='ant',--[[Dockerfile]]Dockerfile='docker build .',--[[Make]]Makefile='make',GNUmakefile='make',makefile='make',--[[Maven]]['pom.xml']='mvn',--[[Ruby]]Rakefile='rake'}
---
--- Builds the current project (based on the buffer's filename or the current
--- working directory) using the shell command from the `build_commands` table.
+-- Builds the project whose root path is *root_directory* or the current project
+-- using the shell command from the `build_commands` table.
-- If a "makefile" type of build file is found, prompts the user for the full
-- build command.
+-- The current project is determined by either the buffer's filename or the
+-- current working directory.
-- Emits `BUILD_OUTPUT` events.
+-- @param root_directory The path to the project to build. The default value is
+-- the current project.
-- @see build_commands
-- @see _G.events
-- @name build
-function M.build() run_command(M.build_commands, events.BUILD_OUTPUT) end
+function M.build(root_directory)
+ if not root_directory then root_directory = io.get_project_root() end
+ if not root_directory then return end
+ for i = 1, #_BUFFERS do _BUFFERS[i]:annotation_clear_all() end
+ -- Determine command.
+ local command = M.build_commands[root_directory]
+ if not command then
+ for build_file, build_command in pairs(M.build_commands) do
+ if lfs.attributes(root_directory..'/'..build_file) then
+ local button, utf8_command = ui.dialogs.inputbox{
+ title = _L['Command'], informative_text = root_directory,
+ text = build_command, button1 = _L['_OK'], button2 = _L['_Cancel']
+ }
+ if button == 1 then command = utf8_command:iconv(_CHARSET, 'UTF-8') end
+ break
+ end
+ end
+ end
+ local working_dir
+ if type(command) == 'function' then command, working_dir = command() end
+ if not command then return end
+ -- Prepare to run the command.
+ preferred_view = view
+ local function emit_output(output)
+ for line in output:gmatch('[^\r\n]+') do
+ events.emit(events.BUILD_OUTPUT, line)
+ end
+ end
+ -- Run the command.
+ cwd = working_dir or root_directory
+ events.emit(event, '> cd '..cwd)
+ events.emit(event, '> '..command:iconv('UTF-8', _CHARSET))
+ proc = assert(spawn(command, cwd, emit_output, emit_output, function(status)
+ events.emit(event, '> exit status: '..status)
+ end))
+end
events.connect(events.BUILD_OUTPUT, print_output)
---
-- Stops the currently running process, if any.
-- @name stop
-function M.stop() if M.proc then M.proc:kill() end end
+function M.stop() if proc then proc:kill() end end
-- Send line as input to process stdin on return.
events.connect(events.CHAR_ADDED, function(code)
- local proc = M.proc
- if code == 10 and proc and proc.status and proc:status() == 'running' and
+ if code == 10 and proc and proc:status() == 'running' and
buffer._type == _L['[Message Buffer]'] then
local line_num = buffer:line_from_position(buffer.current_pos) - 1
proc:write((buffer:get_line(line_num)))
@@ -275,17 +312,22 @@ events.connect(events.CHAR_ADDED, function(code)
end)
---
--- List of warning and error string patterns that match various compile and run
--- warnings and errors.
--- Patterns contain filename, line number, and optional warning or error message
--- captures for single lines. When a warning or error message is double-clicked,
--- the user is taken to the point of warning/error.
--- When adding to this list, use `(.-)` to match filenames and `(%d+)` to match
--- line numbers. Also keep in mind that patterns are matched in sequential
--- order; once a pattern matches, no more are tried.
+-- Map of file extensions and lexer names to their associated lists of string
+-- patterns that match warning and error messages emitted by compile and run
+-- commands for those file extensions and lexers.
+-- Patterns match single lines and contain captures for a filename, line number,
+-- column number (optional), and warning or error message (optional). When a
+-- warning or error message is double-clicked, the user is taken to the source
+-- of that warning/error.
+-- Note: `(.-)` captures in patterns are interpreted as filenames; `(%d+)`
+-- captures are interpreted as line numbers first, and then column numbers; and
+-- any other capture is treated as warning/error message text.
-- @class table
-- @name error_patterns
-M.error_patterns = {--[[ANTLR]]'^error%(%d+%): (.-):(%d+):%d+: (.+)$','^warning%(%d+%): (.-):(%d+):%d+: (.+)$',--[[AWK]]'^awk: (.-): line (%d+): (.+)$',--[[ChucK]]'^%[(.-)%]:line%((%d+)%)%.char%(%d+%): (.+)$',--[[CMake]]'^CMake Error at (.-):(%d+)',--[[Dot]]'^Error: (.-):(%d+): (.+)$',--[[Eiffel]]'^Line (%d+) columns? .- in .- %((.-)%):$','^line (%d+) column %d+ file (.-)$',--[[CoffeeScript,LitCoffee]]'^%s+at .-%((.-):(%d+):%d+, .-%)$',--[[Groovy,Java,Javascript]]'^%s+at .-%((.-):(%d+):?%d*%)$',--[[Icon]]'^File (.-); Line (%d+) # (.+)$',--[[JavaScript]]'^%s+at (.-):(%d+):%d+$',--[[GNUPlot]]'^"(.-)", line (%d+): (.+)$',--[[Lua]]'^luac?: (.-):(%d+): (.+)$',--[[Prolog]]'^warning: (.-):(%d+): (.+)$',--[[OCaml,Python]]'^%s*File "(.-)", line (%d+)',--[[Rexx]]'^Error %d+ running "(.-)", line (%d+): (.+)$',--[[Sass]]'^WARNING on line (%d+) of (.-):$','^%s+on line (%d+) of (.-)$',--[[Tcl]]'^%s*%(file "(.-)" line (%d+)%)$',--[[Actionscript]]'^(.-)%((%d+)%): col %d+ (.+)$',--[[CUDA,D]]'^(.-)%((%d+)%): ([Ee]rror.+)$',--[[Boo,C#,F#,Nemerle,VB]]'^(.-)%((%d+),%d+%): (.+)$',--[[Pascal,Nim]]'^(.-)%((%d+),?%s*%d*%) (%w+:.+)$',--[[Ada,C/C++,Haskell,LilyPond,Objective C,Prolog]]'^(.-):(%d+):%d+:%s*(.*)$',--[[Fortran,Vala]]'^(.-):(%d+)[%.%-][%.%d%-]+:%s*(.*)$',--[[CMake,Javascript]]'^(.-):(%d+):$',--[[Pure]]'^(.-), line (%d+): (.+)$',--[[Python]]'^.-: %(\'([^\']+)\', %(\'(.-)\', (%d+), %d,','^.-: (.+) %((.-), line (%d+)%)$',--[[Shell (Bash)]]'^(.-): line (%d+): (.+)$',--[[Shell (sh)]]'^(.-): (%d+): %1: (.+)$',--[[Erlang,Forth,Groovy,Go,Java,LilyPond,Makefile,Pike,Ruby,Scala,Smalltalk,SNOBOL4]]'^%s*(.-):%s*(%d+):%s*(.+)$',--[[Less]]'^(.+) in (.-) on line (%d+), column %d+:$',--[[PHP]]'^(.+) in (.-) on line (%d+)$',--[[Gap]]'^(.+) in (.-) line (%d+)$',--[[Perl]]'^(.+) at (.-) line (%d+)',--[[APDL,IDL,REBOL,Verilog,VHDL:proprietary]]--[[ASP,CSS,Desktop,diff,django,gettext,Gtkrc,HTML,ini,JSON,JSP,Markdown,Postscript,Properties,R,RHTML,XML:none]]--[[Batch,BibTeX,ConTeXt,Dockerfile,GLSL,Inform,Io,Lisp,MoonScript,Scheme,SQL,TeX:cannot parse]]}
+M.error_patterns = {actionscript={'^(.-)%((%d+)%): col: (%d+) (.+)$'},ada={'^(.-):(%d+):(%d+):%s*(.*)$','^[^:]+: (.-):(%d+) (.+)$'},ansi_c={'^(.-):(%d+):(%d+): (.+)$'},antlr={'^error%(%d+%): (.-):(%d+):(%d+): (.+)$','^warning%(%d+%): (.-):(%d+):(%d+): (.+)$'},--[[ANTLR]]g={'^error%(%d+%): (.-):(%d+):(%d+): (.+)$','^warning%(%d+%): (.-):(%d+):(%d+): (.+)$'},asm={'^(.-):(%d+): (.+)$'},awk={'^awk: (.-):(%d+): (.+)$'},boo={'^(.-)%((%d+),(%d+)%): (.+)$'},caml={'^%s*File "(.-)", line (%d+), characters (%d+)'},chuck={'^(.-)line%((%d+)%)%.char%((%d+)%): (.+)$'},cmake={'^CMake Error at (.-):(%d+)','^(.-):(%d+):$'},coffeescript={'^(.-):(%d+):(%d+): (.+)$'},context={'error on line (%d+) in file (.-): (.+)$'},cpp={'^(.-):(%d+):(%d+): (.+)$'},csharp={'^(.-)%((%d+),(%d+)%): (.+)$'},cuda={'^(.-)%((%d+)%): (error.+)$'},dart={"^'(.-)': error: line (%d+) pos (%d+): (.+)$",'%(file://(.-):(%d+):(%d+)%)'},dmd={'^(.-)%((%d+)%): (Error.+)$'},dot={'^Warning: (.-): (.+) in line (%d+)'},eiffel={'^Line (%d+) columns? .- in .- %((.-)%):$','^line (%d+) column (%d+) file (.-)$'},elixir={'^(.-):(%d+): (.+)$','Error%) (.-):(%d+): (.+)$'},erlang={'^(.-):(%d+): (.+)$'},faust={'^(.-):(%d+):(.+)$'},forth={'^(.-):(%d+): (.+)$'},fortran={'^(.-):(%d+)%D+(%d+):%s*(.*)$'},fsharp={'^(.-)%((%d+),(%d+)%): (.+)$'},gap={'^(.+) in (.-) line (%d+)$'},gnuplot={'^"(.-)", line (%d+): (.+)$'},go={'^(.-):(%d+): (.+)$'},groovy={'^%s+at .-%((.-):(%d+)%)$','^(.-):(%d+): (.+)$'},haskell={'^(.-):(%d+):(%d+):%s*(.*)$'},icon={'^File (.-); Line (%d+) # (.+)$','^.-from line (%d+) in (.-)$'},java={'^%s+at .-%((.-):(%d+)%)$','^(.-):(%d+): (.+)$'},javascript={'^%s+at .-%((.-):(%d+):(%d+)%)$','^%s+at (.-):(%d+):(%d+)$','^(.-):(%d+):?$'},ltx={'^(.-):(%d+): (.+)$'},less={'^(.+) in (.-) on line (%d+), column (%d+):$'},lilypond={'^(.-):(%d+):(%d+):%s*(.*)$'},litcoffee={'^(.-):(%d+):(%d+): (.+)$'},lua={'^luac?: (.-):(%d+): (.+)$'},makefile={'^(.-):(%d+): (.+)$'},nemerle={'^(.-)%((%d+),(%d+)%): (.+)$'},nim={'^(.-)%((%d+), (%d+)%) (%w+:.+)$'},objective_c={'^(.-):(%d+):(%d+): (.+)$'},pascal={'^(.-)%((%d+),(%d+)%) (%w+:.+)$'},perl={'^(.+) at (.-) line (%d+)'},php={'^(.+) in (.-) on line (%d+)$'},pike={'^(.-):(%d+):(.+)$'},prolog={'^(.-):(%d+):(%d+): (.+)$','^(.-):(%d+): (.+)$'},pure={'^(.-), line (%d+): (.+)$'},python={'^%s*File "(.-)", line (%d+)'},rexx={'^Error %d+ running "(.-)", line (%d+): (.+)$'},ruby={'^%s+from (.-):(%d+):','^(.-):(%d+):%s*(.+)$'},rust={'^(.-):(%d+):(%d+): (.+)$',"panicked at '([^']+)', (.-):(%d+)"},sass={'^WARNING on line (%d+) of (.-):$','^%s+on line (%d+) of (.-)$'},scala={'^%s+at .-%((.-):(%d+)%)$','^(.-):(%d+): (.+)$'},sh={'^(.-): (%d+): %1: (.+)$'},bash={'^(.-): line (%d+): (.+)$'},zsh={'^(.-):(%d+): (.+)$'},smalltalk={'^(.-):(%d+): (.+)$','%((.-):(%d+)%)$'},snobol4={'^(.-):(%d+): (.+)$'},tcl={'^%s*%(file "(.-)" line (%d+)%)$'},tex={'^(.-):(%d+): (.+)$'},vala={'^(.-):(%d+)%.(%d+)[%-%.%d]+: (.+)$','^(.-):(%d+):(%d+): (.+)$'},vb={'^(.-)%((%d+),(%d+)%): (.+)$'}}
+-- Note: APDL,IDL,REBOL,Verilog,VHDL are proprietary.
+-- Note: ASP,CSS,Desktop,diff,django,gettext,Gtkrc,HTML,ini,JSON,JSP,Markdown,Postscript,Properties,R,RHTML,XML don't have parse-able errors.
+-- Note: Batch,BibTeX,ConTeXt,Dockerfile,GLSL,Inform,Io,Lisp,MoonScript,Scheme,SQL,TeX cannot be parsed for one reason or another.
-- Returns whether or not the given buffer is a message buffer.
local function is_msg_buf(buf) return buf._type == _L['[Message Buffer]'] end
@@ -296,14 +338,14 @@ local function is_msg_buf(buf) return buf._type == _L['[Message Buffer]'] end
-- on boolean *next*. Displays an annotation with the warning or error message
-- if possible.
-- @param line The line number in the message buffer that contains the
--- compile/run warning/error to go to.
+-- compile/run warning or error to go to.
-- @param next Optional flag indicating whether to go to the next recognized
-- warning/error or the previous one. Only applicable when *line* is `nil` or
-- `false`.
-- @see error_patterns
--- @see cwd
-- @name goto_error
function M.goto_error(line, next)
+ if not cwd then return end -- no previously run command
local msg_view, msg_buf = nil, nil
for i = 1, #_VIEWS do
if is_msg_buf(_VIEWS[i].buffer) then msg_view = i break end
@@ -329,100 +371,34 @@ function M.goto_error(line, next)
line = (next and math.min or math.max)(wline, eline)
if line == -1 then return end
end
- buffer:goto_line(line)
+ textadept.editing.goto_line(line + 1) -- ensure visible
-- Goto the warning or error and show an annotation.
local line = buffer:get_line(line):match('^[^\r\n]*')
- local error = get_error(line:iconv(_CHARSET, 'UTF-8'))
+ local error = scan_for_error(line:iconv(_CHARSET, 'UTF-8'))
if not error then return end
textadept.editing.select_line()
- ui.goto_file(M.cwd..'/'..error.filename, true, preferred_view, true)
- local line_num, message = error.line, error.message
- textadept.editing.goto_line(line_num)
- if message then
- buffer.annotation_text[line_num - 1] = message
+ ui.goto_file(cwd..(not WIN32 and '/' or '\\')..error.filename, true,
+ preferred_view, true)
+ textadept.editing.goto_line(error.line)
+ if error.column then
+ buffer:goto_pos(buffer:find_column(error.line - 1, error.column - 1))
+ end
+ if error.message then
+ buffer.annotation_text[error.line - 1] = error.message
-- Style number 8 is the error style.
- if not error.warning then buffer.annotation_style[line_num - 1] = 8 end
+ if not error.warning then buffer.annotation_style[error.line - 1] = 8 end
end
end
events.connect(events.KEYPRESS, function(code)
- if keys.KEYSYMS[code] == '\n' and is_msg_buf(buffer) and M.cwd and
- get_error(buffer:get_cur_line():match('^[^\r\n]*')) then
+ if keys.KEYSYMS[code] == '\n' and is_msg_buf(buffer) and
+ scan_for_error(buffer:get_cur_line():match('^[^\r\n]*')) then
M.goto_error(buffer:line_from_position(buffer.current_pos))
return true
end
end)
events.connect(events.DOUBLE_CLICK, function(_, line)
- if is_msg_buf(buffer) and M.cwd then M.goto_error(line) end
-end)
-
----
--- Map of file extensions or lexer names to their associated syntax checker
--- command line strings or functions that return such strings.
--- `%f` in command line strings represents the file to check the syntax of.
--- Upon saving a source file, this table is consulted for potentially running a
--- syntax checking utility on that file. This usually only makes sense for
--- interpreted languages and markup languages.
--- @class table
--- @name syntax_commands
-M.syntax_commands = {awk='gawk --source "BEGIN{exit(0)} END{exit(0)}" --file "%f"',bash = function() return (buffer:get_line(0):match('^#!.+/([^/%s]+)') or 'bash')..' -n "%f"' end,coffeescript='coffee -cp "%f"',css='csslint --format=compact --quiet "%f"',fish='fish -n "%f"',go='gofmt -l "%f"',html='tidy -e -q -utf8 "%f"',javascript='jshint "%f"',less='lessc --lint --no-color "%f"',litcoffee='coffee -cp "%f"',lua='luac -p "%f"',perl='perl -c -X "%f"',php='php -l "%f"',python=function() return ([[python -c "compile(open('%f').read(),'%f','exec',0,1)"]]):gsub('%%f', (buffer.filename:gsub('\\', '\\\\\\\\'))) end,ruby='ruby -c "%f"',sass='sass -c -q "%f"',snobol4='snobol4 -b -n "%f"',xml='xmllint "%f"',}
-
----
--- Map of file extensions or lexer names to patterns that match their respective
--- syntax-checkers' error messages or functions that return such patterns.
--- Patterns contain line number, optional column number, and error message
--- captures.
--- When adding to this map, use `(%d+)` to match line and column numbers.
--- `(%s*)` may also be used to match column numbers for visual error messages.
--- @class table
--- @name syntax_error_patterns
-M.syntax_error_patterns = {awk=':(%d+): (%s*)^ ([^\r\n]+)',bash='[:%s](%d+): ([^\r\n]+)',coffeescript='In [^,]+, (.-) on line (%d+):?([^\r\n]*)',css='line (%d+), col (%d+), ([^\r\n]+)',fish='fish: ([^\r\n]+).-line (%d+).:',go=':(%d+):(%d+): ([^\r\n]+)',html='line (%d+) column (%d+) %- Error: ([^\r\n]+)',javascript='line (%d+), col (%d+), ([^\r\n]+)',less='^(.-) in .- on line (%d+), column (%d+):',litcoffee='In [^,]+, (.-) on line (%d+):?([^\r\n]*)',lua=':(%d+): ([^\r\n]+)',perl='^(.-) at .- line (%d+)',php='^(.-) in .- on line (%d+)',python='", line (%d+)[\r\n]+.-(%w+: [^\r\n]+)',ruby=':(%d+): ([^\r\n]+).-[\r\n]+(%s*)^?[\r\n]*$',sass='^([^\r\n]+).-on line (%d+)',snobol4='^(.-):(%d+): ([^\r\n]+)',xml=':(%d+): ([^\r\n]+).-[\r\n]+(%s*)^',}
-
--- Check syntax upon saving a file.
-events.connect(events.FILE_AFTER_SAVE, function(filename)
- if not M.CHECK_SYNTAX then return end
- -- Determine the syntax checker command.
- local ext, lexer = buffer.filename:match('[^.]+$'), buffer:get_lexer()
- local command = M.syntax_commands[ext] or M.syntax_commands[lexer]
- local patt = M.syntax_error_patterns[ext] or M.syntax_error_patterns[lexer]
- if type(command) == 'function' then command = command() end
- if type(patt) == 'function' then patt = patt() end
- if not command or not patt then return end
- -- Run the syntax checker command and look for errors.
- buffer:annotation_clear_all()
- local out = {}
- local output = function(output) out[#out + 1] = output end
- spawn(command:gsub('%%f', filename), nil, output, output, function()
- local captures = {message = '', table.concat(out):match(patt)}
- if #captures == 0 then return end
- -- Parse out the line, column, and error message.
- for detail in patt:gmatch('[^%%](%b())') do
- if detail == '(%d+)' then
- local source = not captures.line and 'line' or 'column'
- captures[source] = tonumber(table.remove(captures, 1)) - 1
- elseif detail == '(%s*)' then
- captures.column = #table.remove(captures, 1)
- else
- captures.message = captures.message..table.remove(captures, 1)
- end
- end
- if not captures.line or not captures.message then return end
- -- Display the annotation and either jump to, or note the position.
- buffer.annotation_text[captures.line] = captures.message
- buffer.annotation_style[captures.line] = 8 -- error style number
- local top_line = buffer:doc_line_from_visible(buffer.first_visible_line)
- local bottom_line = buffer:doc_line_from_visible(buffer.first_visible_line +
- buffer.lines_on_screen) - 1
- if M.GOTO_SYNTAX_ERRORS then
- buffer:goto_pos(buffer:find_column(captures.line, captures.column or 0))
- elseif captures.line < top_line or captures.line > bottom_line then
- local line = buffer:line_from_position(buffer.current_pos)
- buffer.annotation_text[line] = string.format('%s %d\n%s', _L['Line:'],
- captures.line + 1,
- captures.message)
- buffer.annotation_style[line] = 8 -- error style number
- end
- end)
+ if is_msg_buf(buffer) then M.goto_error(line) end
end)
return M