aboutsummaryrefslogtreecommitdiffhomepage
path: root/modules
diff options
context:
space:
mode:
authorGravatar mitchell <70453897+667e-11@users.noreply.github.com>2020-03-13 17:33:34 -0400
committerGravatar mitchell <70453897+667e-11@users.noreply.github.com>2020-03-13 17:33:34 -0400
commit753b949ae0ff0f574a7a8247ff936be623d815c3 (patch)
treed7caf986f29b92c11677a8ed480f53ca8367dc5b /modules
parent2bf12e0e8ca11e37277a12123d5f6b5045d9c781 (diff)
More code cleanup, refactoring, and reformatting.
Diffstat (limited to 'modules')
-rw-r--r--modules/textadept/command_entry.lua2
-rw-r--r--modules/textadept/editing.lua2
-rw-r--r--modules/textadept/menu.lua105
-rw-r--r--modules/textadept/run.lua143
4 files changed, 128 insertions, 124 deletions
diff --git a/modules/textadept/command_entry.lua b/modules/textadept/command_entry.lua
index 87f1465a..5df63a25 100644
--- a/modules/textadept/command_entry.lua
+++ b/modules/textadept/command_entry.lua
@@ -78,7 +78,7 @@ local function run_lua(code)
if type(result) == 'table' then
local items = {}
for k, v in pairs(result) do
- items[#items + 1] = string.format('%s = %s', tostring(k), tostring(v))
+ items[#items + 1] = string.format('%s = %s', k, v)
end
table.sort(items)
result = string.format('{%s}', table.concat(items, ', '))
diff --git a/modules/textadept/editing.lua b/modules/textadept/editing.lua
index 9d2f5e7b..bc5d8ffa 100644
--- a/modules/textadept/editing.lua
+++ b/modules/textadept/editing.lua
@@ -185,7 +185,7 @@ end)
-- Auto-indent on return.
events.connect(events.CHAR_ADDED, function(code)
- if not M.auto_indent or code ~= 10 then return end
+ if not M.auto_indent or code ~= string.byte('\n') then return end
local line = buffer:line_from_position(buffer.current_pos)
if line > 0 and buffer:get_line(line - 1):find('^[\r\n]+$') and
buffer:get_line(line):find('^[^\r\n]') then
diff --git a/modules/textadept/menu.lua b/modules/textadept/menu.lua
index 24790f96..df800e02 100644
--- a/modules/textadept/menu.lua
+++ b/modules/textadept/menu.lua
@@ -42,7 +42,7 @@ local function set_encoding(encoding)
end
local function open_page(url)
local cmd = (WIN32 and 'start ""') or (OSX and 'open') or 'xdg-open'
- os.spawn(string.format('%s "%s"', cmd, not OSX and url or 'file://'..url))
+ os.spawn(string.format('%s "%s"', cmd, not OSX and url or 'file://' .. url))
end
---
@@ -91,7 +91,7 @@ local default_menubar = {
SEPARATOR,
{_L['Match Brace'], function()
local match_pos = buffer:brace_match(buffer.current_pos, 0)
- if match_pos >= 0 then buffer:goto_pos(match_pos) end
+ if match_pos ~= -1 then buffer:goto_pos(match_pos) end
end},
{_L['Complete Word'], function()
textadept.editing.autocomplete('word')
@@ -120,9 +120,9 @@ local default_menubar = {
{_L['Enclose as XML Tags'], function()
buffer:begin_undo_action()
enc('<', '>')
- local pos = buffer.current_pos
- while buffer.char_at[pos - 1] ~= 60 do pos = pos - 1 end -- '<'
- buffer:insert_text(-1, '</'..buffer:text_range(pos, buffer.current_pos))
+ local s, e = buffer.current_pos, buffer.current_pos
+ while buffer.char_at[s - 1] ~= 60 do s = s - 1 end -- '<'
+ buffer:insert_text(-1, '</' .. buffer:text_range(s, e))
buffer:end_undo_action()
end},
{_L['Enclose as Single XML Tag'], function() enc('<', ' />') end},
@@ -177,7 +177,7 @@ local default_menubar = {
-- Compare the base run/compile command with the one for the current
-- file. The difference is any additional arguments set previously.
base_commands[i] = commands[buffer.filename:match('[^.]+$')] or
- commands[buffer:get_lexer()] or ''
+ commands[buffer:get_lexer()] or ''
local current_command = commands[buffer.filename] or ''
local args = current_command:sub(#base_commands[i] + 2)
utf8_args[i] = args:iconv('UTF-8', _CHARSET)
@@ -191,8 +191,8 @@ local default_menubar = {
for i, commands in ipairs{run_commands, compile_commands} do
-- Add the additional arguments to the base run/compile command and set
-- the new command to be the one used for the current file.
- commands[buffer.filename] = base_commands[i]..' '..
- utf8_args[i]:iconv(_CHARSET, 'UTF-8')
+ commands[buffer.filename] = string.format('%s %s', base_commands[i],
+ utf8_args[i]:iconv(_CHARSET, 'UTF-8'))
end
end},
{_L['Build'], textadept.run.build},
@@ -249,14 +249,14 @@ local default_menubar = {
{_L['Show Documentation'], textadept.editing.show_documentation},
{_L['Show Style'], function()
local char = buffer:text_range(buffer.current_pos,
- buffer:position_after(buffer.current_pos))
+ buffer:position_after(buffer.current_pos))
if char == '' then return end -- end of buffer
local bytes = string.rep(' 0x%X', #char):format(char:byte(1, #char))
local style = buffer.style_at[buffer.current_pos]
- local text = string.format("'%s' (U+%04X:%s)\n%s %s\n%s %s (%d)", char,
- utf8.codepoint(char), bytes, _L['Lexer'],
- buffer:get_lexer(true), _L['Style'],
- buffer:name_of_style(style), style)
+ local text = string.format(
+ "'%s' (U+%04X:%s)\n%s %s\n%s %s (%d)", char, utf8.codepoint(char),
+ bytes, _L['Lexer'], buffer:get_lexer(true), _L['Style'],
+ buffer:name_of_style(style), style)
buffer:call_tip_show(buffer.current_pos, text)
end}
},
@@ -343,14 +343,14 @@ local default_menubar = {
},
{
title = _L['Help'],
- {_L['Show Manual'], function() open_page(_HOME..'/doc/manual.html') end},
- {_L['Show LuaDoc'], function() open_page(_HOME..'/doc/api.html') end},
+ {_L['Show Manual'], function() open_page(_HOME .. '/doc/manual.html') end},
+ {_L['Show LuaDoc'], function() open_page(_HOME .. '/doc/api.html') end},
SEPARATOR,
{_L['About'], function()
- ui.dialogs.msgbox({
+ ui.dialogs.msgbox{
title = 'Textadept', text = _RELEASE, informative_text = _COPYRIGHT,
- icon_file = _HOME..'/core/images/ta_64x64.png'
- })
+ icon_file = _HOME .. '/core/images/ta_64x64.png'
+ }
end}
}
}
@@ -403,8 +403,8 @@ local function get_gdk_key(key_seq)
local mods, key = key_seq:match('^([cams]*)(.+)$')
if not mods or not key then return nil end
local modifiers = ((mods:find('s') or key:lower() ~= key) and 1 or 0) +
- (mods:find('c') and 4 or 0) + (mods:find('a') and 8 or 0) +
- (mods:find('m') and 0x10000000 or 0)
+ (mods:find('c') and 4 or 0) + (mods:find('a') and 8 or 0) +
+ (mods:find('m') and 0x10000000 or 0)
local code = string.byte(key)
if #key > 1 or code < 32 then
for i, s in pairs(keys.KEYSYMS) do
@@ -424,18 +424,17 @@ end
local function read_menu_table(menu, contextmenu)
local gtkmenu = {}
gtkmenu.title = menu.title
- for i = 1, #menu do
- if menu[i].title then
- gtkmenu[#gtkmenu + 1] = read_menu_table(menu[i], contextmenu)
- else
- local label, f = menu[i][1], menu[i][2]
- local menu_id = not contextmenu and #menu_items + 1 or
- #contextmenu_items + 1000 + 1
- local key, mods = get_gdk_key(key_shortcuts[tostring(f)])
- gtkmenu[#gtkmenu + 1] = {label, menu_id, key, mods}
- if f then
+ for _, item in ipairs(menu) do
+ if item.title then
+ gtkmenu[#gtkmenu + 1] = read_menu_table(item, contextmenu)
+ else -- item = {label, function}
+ local menu_id =
+ not contextmenu and #menu_items + 1 or #contextmenu_items + 1000 + 1
+ local key, mods = get_gdk_key(key_shortcuts[tostring(item[2])])
+ gtkmenu[#gtkmenu + 1] = {item[1], menu_id, key, mods}
+ if item[2] then
local menu_items = not contextmenu and menu_items or contextmenu_items
- menu_items[menu_id < 1000 and menu_id or menu_id - 1000] = menu[i]
+ menu_items[menu_id < 1000 and menu_id or menu_id - 1000] = item
end
end
end
@@ -456,8 +455,8 @@ local function proxy_menu(menu, update, menubar)
if type(k) == 'number' or k == 'title' then
v = menu[k]
elseif type(k) == 'string' then
- for i = 1, #menu do
- if menu[i].title == k or menu[i][1] == k then v = menu[i] break end
+ for _, item in ipairs(menu) do
+ if item.title == k or item[1] == k then v = item break end
end
end
return type(v) == 'table' and proxy_menu(v, update, menubar or menu) or v
@@ -497,6 +496,8 @@ local function set_menubar(menubar)
end
events.connect(events.INITIALIZED, function() set_menubar(default_menubar) end)
-- Define menu proxy for use by keys.lua and user scripts.
+-- Do not use an update function because this is expensive at startup, and
+-- `events.INITIALIZED` will create the first visible menubar and proper proxy.
proxies.menubar = proxy_menu(default_menubar, function() end)
-- Sets `ui.context_menu` and `ui.tab_context_menu` from menu item lists
@@ -514,17 +515,22 @@ proxies.menubar = proxy_menu(default_menubar, function() end)
-- @see ui.menu
local function set_contextmenus(buffer_menu, tab_menu)
contextmenu_items = {} -- reset
- local menu = buffer_menu or default_context_menu
- ui.context_menu = ui.menu(read_menu_table(menu, true))
- proxies.context_menu = proxy_menu(menu, set_contextmenus)
- menu = tab_menu or default_tab_context_menu
- ui.tab_context_menu = ui.menu(read_menu_table(menu, true))
- proxies.tab_context_menu = proxy_menu(menu, function()
- set_contextmenus(nil, menu)
- end)
+ local menus = {
+ context_menu = buffer_menu or default_context_menu,
+ tab_context_menu = tab_menu or default_tab_context_menu
+ }
+ for name, menu in pairs(menus) do
+ ui[name] = ui.menu(read_menu_table(menu, true))
+ proxies[name] = proxy_menu(menu, function()
+ set_contextmenus(menus.context_menu, menus.tab_context_menu)
+ end)
+ end
end
events.connect(events.INITIALIZED, set_contextmenus)
-- Define menu proxies for use by user scripts.
+-- Do not use an update function because this is expensive at startup, and
+-- `events.INITIALIZED` will create these visible menus and their proper
+-- proxies.
proxies.context_menu = proxy_menu(default_context_menu, function() end)
proxies.tab_context_menu = proxy_menu(default_tab_context_menu, function() end)
@@ -532,8 +538,8 @@ proxies.tab_context_menu = proxy_menu(default_tab_context_menu, function() end)
events.connect(events.MENU_CLICKED, function(menu_id)
local menu_item = menu_id < 1000 and menu_items or contextmenu_items
local action = menu_item[menu_id < 1000 and menu_id or menu_id - 1000][2]
- assert(type(action) == 'function',
- _L['Unknown command:']..' '..tostring(action))
+ assert(type(action) == 'function', string.format(
+ '%s %s', _L['Unknown command:'], action))
action()
end)
@@ -545,13 +551,14 @@ function M.select_command()
-- Builds the item tables for the filtered list dialog.
-- @param menu The menu to read from.
local function build_command_tables(menu)
- for i = 1, #menu do
- if menu[i].title then
- build_command_tables(menu[i])
- elseif menu[i][1] ~= '' then
- local label = menu.title and menu.title..': '..menu[i][1] or menu[i][1]
+ for _, item in ipairs(menu) do
+ if item.title then
+ build_command_tables(item)
+ elseif item[1] ~= '' then -- item = {label, function}
+ local label =
+ menu.title and string.format('%s: %s', menu.title, item[1]) or item[1]
items[#items + 1] = label:gsub('_([^_])', '%1')
- items[#items + 1] = key_shortcuts[tostring(menu[i][2])] or ''
+ items[#items + 1] = key_shortcuts[tostring(item[2])] or ''
end
end
end
diff --git a/modules/textadept/run.lua b/modules/textadept/run.lua
index f23babd7..cd7f7b51 100644
--- a/modules/textadept/run.lua
+++ b/modules/textadept/run.lua
@@ -73,33 +73,33 @@ local proc, cwd, preferred_view
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
+ for _, patt in ipairs(patterns) do
+ if not message:find(patt) 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
+ local detail, i = {message:match(patt)}, 1
+ for capture in patt:gmatch('[^%%](%b())') do
if capture == '(.-)' then
- details.filename = details[j]
+ detail.filename = detail[i]
elseif capture == '(%d+)' then
- local line_or_column = not details.line and 'line' or 'column'
- details[line_or_column] = tonumber(details[j])
+ local line_or_column = not detail.line and 'line' or 'column'
+ detail[line_or_column] = tonumber(detail[i])
else
- details.message = details[j]
+ detail.message = detail[i]
end
- j = j + 1
+ i = i + 1
end
- details.warning = message:lower():find('warning') and
- not message:lower():find('error')
+ detail.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('[^/\\.]+$')
+ if ext_or_lexer then return detail end
+ local ext = detail.filename:match('[^/\\.]+$')
local lexer = textadept.file_types.extensions[ext]
- if ext == key or lexer == key then return details end
+ if ext == key or lexer == key then return detail end
::continue::
end
::continue::
@@ -117,14 +117,14 @@ end
-- run commands.
local function print_line(line, ext_or_lexer)
local error = scan_for_error(line, ext_or_lexer)
- ui.silent_print = (M.run_in_background or ext_or_lexer or
- not line:find('^> ') or line:find('^> exit')) and true
+ ui.silent_print = M.run_in_background or ext_or_lexer or
+ not line:find('^> ') or line:find('^> exit')
ui.print(not error and line or line:iconv('UTF-8', _CHARSET))
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)
+ buffer:marker_add(
+ buffer.line_count - 2, error.warning and M.MARK_WARNING or M.MARK_ERROR)
end
end
@@ -137,19 +137,46 @@ local output_buffer
-- run commands.
local function print_output(output, ext_or_lexer)
if output then
- if output_buffer then output = output_buffer..output end
+ if output_buffer then output = output_buffer .. output end
local remainder = 1
for line, e in output:gmatch('([^\r\n]*)\r?\n()') do
print_line(line, ext_or_lexer)
remainder = e
end
- output_buffer = remainder <= #output and string.sub(output, remainder)
+ output_buffer = remainder <= #output and output:sub(remainder)
elseif output_buffer then
print_line(output_buffer, ext_or_lexer)
output_buffer = nil
end
end
+-- Runs command *command* in working directory *dir*, emitting events of type
+-- *event* with any output received.
+-- @param command String command to run, or a function returning such a string
+-- and optional working directory. A returned working directory overrides
+-- *dir*.
+-- @param dir String working directory to run *command* in.
+-- @param event String event name to emit command output with.
+-- @param macros Optional table of '%[char]' macros to expand within *command*.
+-- @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 run_command(command, dir, event, macros, ext_or_lexer)
+ local working_dir
+ if type(command) == 'function' then command, working_dir = command() end
+ if not command then return end
+ if macros then command = command:gsub('%%%a', macros) end
+ preferred_view = view
+ local function emit(output) events.emit(event, output, ext_or_lexer) end
+ cwd = (working_dir or dir):gsub('[/\\]$', '')
+ events.emit(event, string.format('> cd %s\n', cwd))
+ events.emit(event, string.format('> %s\n', command:iconv('UTF-8', _CHARSET)))
+ proc = assert(os.spawn(command, cwd, emit, emit, function(status)
+ emit() -- flush
+ events.emit(event, string.format('> exit status: %d\n', status))
+ 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`.
@@ -158,37 +185,21 @@ local function compile_or_run(filename, commands)
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]
+ 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) events.emit(event, output, ext_or_lexer) end
- -- Run the command.
- cwd = (working_dir or dirname):gsub('[/\\]$', '')
- if cwd ~= dirname then events.emit(event, '> cd '..cwd..'\n') end
- events.emit(event, '> '..command:iconv('UTF-8', _CHARSET)..'\n')
- proc = assert(os.spawn(command, cwd, emit, emit, function(status)
- emit() -- flush
- events.emit(event, '> exit status: '..status..'\n')
- end))
+ events.RUN_OUTPUT
+ local macros = {
+ ['%p'] = filename, ['%d'] = dirname, ['%f'] = basename,
+ ['%e'] = basename:match('^(.+)%.') -- no extension
+ }
+ run_command(command, dirname, event, macros, commands[ext] and ext or lexer)
end
---
@@ -287,11 +298,10 @@ function M.build(root_directory)
if not root_directory then return end
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
+ if lfs.attributes(string.format('%s/%s', 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']
@@ -301,20 +311,7 @@ function M.build(root_directory)
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) events.emit(events.BUILD_OUTPUT, output) end
- -- Run the command.
- cwd = (working_dir or root_directory):gsub('[/\\]$', '')
- events.emit(events.BUILD_OUTPUT, '> cd '..cwd..'\n')
- events.emit(events.BUILD_OUTPUT, '> '..command:iconv('UTF-8', _CHARSET)..'\n')
- proc = assert(os.spawn(command, cwd, emit, emit, function(status)
- emit() -- flush
- events.emit(events.BUILD_OUTPUT, '> exit status: '..status..'\n')
- end))
+ run_command(command, root_directory, events.BUILD_OUTPUT)
end
events.connect(events.BUILD_OUTPUT, print_output)
@@ -325,7 +322,7 @@ 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)
- if code == 10 and proc and proc:status() == 'running' and
+ if code == string.byte('\n') 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)))
@@ -379,7 +376,7 @@ function M.goto_error(line, next)
-- If no line was given, find the next warning or error marker.
if not assert_type(line, 'number/nil', 1) and next ~= nil then
- local f = buffer['marker_'..(next and 'next' or 'previous')]
+ local f = next and buffer.marker_next or buffer.marker_previous
line = buffer:line_from_position(buffer.current_pos)
local wrapped = false
::retry::
@@ -398,25 +395,25 @@ function M.goto_error(line, next)
goto retry
end
end
- textadept.editing.goto_line(line) -- ensure visible
+ buffer:goto_line(line)
-- Goto the warning or error and show an annotation.
local line = buffer:get_line(line):match('^[^\r\n]*')
- local error = scan_for_error(line:iconv(_CHARSET, 'UTF-8'))
- if not error then return end
+ local detail = scan_for_error(line:iconv(_CHARSET, 'UTF-8'))
+ if not detail then return end
textadept.editing.select_line()
- if not error.filename:find(not WIN32 and '^/' or '^%a:[/\\]') then
- error.filename = cwd..(not WIN32 and '/' or '\\')..error.filename
+ if not detail.filename:find(not WIN32 and '^/' or '^%a:[/\\]') then
+ detail.filename = cwd .. (not WIN32 and '/' or '\\') .. detail.filename
end
- ui.goto_file(error.filename, true, preferred_view, true)
- textadept.editing.goto_line(error.line - 1)
- if error.column then
- buffer:goto_pos(buffer:find_column(error.line - 1, error.column - 1))
+ ui.goto_file(detail.filename, true, preferred_view, true)
+ textadept.editing.goto_line(detail.line - 1)
+ if detail.column then
+ buffer:goto_pos(buffer:find_column(detail.line - 1, detail.column - 1))
end
- if error.message then
- buffer.annotation_text[error.line - 1] = error.message
+ if detail.message then
+ buffer.annotation_text[detail.line - 1] = detail.message
-- Style number 8 is the error style.
- if not error.warning then buffer.annotation_style[error.line - 1] = 8 end
+ if not detail.warning then buffer.annotation_style[detail.line - 1] = 8 end
end
end
events.connect(events.KEYPRESS, function(code)