aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--modules/textadept/command_entry.lua40
-rw-r--r--modules/textadept/init.lua2
-rw-r--r--modules/textadept/keys.lua459
-rw-r--r--modules/textadept/menu.lua394
4 files changed, 467 insertions, 428 deletions
diff --git a/modules/textadept/command_entry.lua b/modules/textadept/command_entry.lua
index fb8726cd..e511527a 100644
--- a/modules/textadept/command_entry.lua
+++ b/modules/textadept/command_entry.lua
@@ -18,10 +18,10 @@ local M = ui.command_entry
--
-- local function complete_lua() ... end
-- local function run_lua() ... end
--- keys['ce'] = {ui.command_entry.enter_mode, 'lua_command'}
+-- keys['ce'] = function() ui.command_entry.enter_mode('lua_command') end
-- keys.lua_command = {
-- ['\t'] = complete_lua,
--- ['\n'] = {ui.command_entry.finish_mode, run_lua}
+-- ['\n'] = function() return ui.command_entry.finish_mode(run_lua) end
-- }
--
-- In this case, `Ctrl+E` opens the command entry and enters "lua_command" key
@@ -43,18 +43,21 @@ module('ui.command_entry')]]
-- @class table
-- @name editing_keys
M.editing_keys = {__index = {
- [not OSX and 'cx' or 'mx'] = {buffer.cut, M},
- [not OSX and 'cc' or 'mc'] = {buffer.copy, M},
- [not OSX and 'cv' or 'mv'] = {buffer.paste, M},
- [not OSX and not CURSES and 'ca' or 'ma'] = {buffer.select_all, M},
- [not OSX and 'cz' or 'mz'] = {buffer.undo, M},
- [not OSX and 'cZ' or 'mZ'] = {buffer.redo, M}, cy = {buffer.redo, M},
+ -- Note: cannot use `M.cut`, `M.copy`, etc. since M is never considered the
+ -- global buffer.
+ [not OSX and 'cx' or 'mx'] = function() M:cut() end,
+ [not OSX and 'cc' or 'mc'] = function() M:copy() end,
+ [not OSX and 'cv' or 'mv'] = function() M:paste() end,
+ [not OSX and not CURSES and 'ca' or 'ma'] = function() M:select_all() end,
+ [not OSX and 'cz' or 'mz'] = function() M:undo() end,
+ [not OSX and 'cZ' or 'mZ'] = function() M:redo() end,
+ [not OSX and 'cy' or '\0'] = function() M:redo() end,
-- Movement keys.
- [(OSX or CURSES) and 'cf' or '\0'] = {buffer.char_right, M},
- [(OSX or CURSES) and 'cb' or '\0'] = {buffer.char_left, M},
- [(OSX or CURSES) and 'ca' or '\0'] = {buffer.vc_home, M},
- [(OSX or CURSES) and 'ce' or '\0'] = {buffer.line_end, M},
- [(OSX or CURSES) and 'cd' or '\0'] = {buffer.clear, M}
+ [(OSX or CURSES) and 'cf' or '\0'] = function() M:char_right() end,
+ [(OSX or CURSES) and 'cb' or '\0'] = function() M:char_left() end,
+ [(OSX or CURSES) and 'ca' or '\0'] = function() M:vc_home() end,
+ [(OSX or CURSES) and 'ce' or '\0'] = function() M:line_end() end,
+ [(OSX or CURSES) and 'cd' or '\0'] = function() M:clear() end
}}
---
@@ -69,7 +72,8 @@ M.editing_keys = {__index = {
-- default value is `'text'`.
-- @param height Optional number of lines to display in the command entry. The
-- default value is `1`.
--- @usage keys['ce'] = {ui.command_entry.enter_mode, 'command_entry'}
+-- @usage keys['ce'] =
+-- function() ui.command_entry.enter_mode('command_entry') end
-- @see _G.keys.MODE
-- @name enter_mode
function M.enter_mode(mode, lexer, height)
@@ -93,7 +97,8 @@ end
-- action with the entered text.
-- @param f Optional function to call. It should accept the command entry text
-- as an argument.
--- @usage keys['\n'] = {ui.command_entry.finish_mode, ui.print}
+-- @usage keys['\n'] =
+-- function() return ui.command_entry.finish_mode(ui.print) end
-- @name finish_mode
function M.finish_mode(f)
if M:auto_c_active() then return false end -- allow Enter to autocomplete
@@ -174,7 +179,10 @@ local function complete_lua()
end
-- Define key mode for entering Lua commands.
-keys.lua_command = {['\t'] = complete_lua, ['\n'] = {M.finish_mode, run_lua}}
+keys.lua_command = {
+ ['\t'] = complete_lua,
+ ['\n'] = function() return M.finish_mode(run_lua) end
+}
-- Configure the command entry's default properties.
events.connect(events.INITIALIZED, function()
diff --git a/modules/textadept/init.lua b/modules/textadept/init.lua
index d6db4cca..457cfa4e 100644
--- a/modules/textadept/init.lua
+++ b/modules/textadept/init.lua
@@ -19,7 +19,7 @@ M.session = require('textadept.session')
M.snippets = require('textadept.snippets')
-- These need to be loaded last.
-M.keys = require('textadept.keys')
M.menu = require('textadept.menu')
+M.keys = require('textadept.keys')
return M
diff --git a/modules/textadept/keys.lua b/modules/textadept/keys.lua
index 6e77911a..c392bc7e 100644
--- a/modules/textadept/keys.lua
+++ b/modules/textadept/keys.lua
@@ -5,9 +5,7 @@ local M = {}
--[[ This comment is for LuaDoc.
---
-- Defines key commands for Textadept.
--- This set of key commands is pretty standard among other text editors. If
--- applicable, load this module second to last in your *~/.textadept/init.lua*,
--- before `textadept.menu`.
+-- This set of key commands is pretty standard among other text editors.
--
-- ## Key Bindings
--
@@ -219,101 +217,6 @@ local M = {}
-- ‡: Ctrl+Enter in Win32 curses.
module('textadept.keys')]]
--- Utility functions.
-M.utils = {
- delete_word = function()
- textadept.editing.select_word()
- buffer:delete_back()
- end,
- autocomplete_symbol = function()
- textadept.editing.autocomplete(buffer:get_lexer(true))
- end,
- enclose_as_xml_tags = function()
- textadept.editing.enclose('<', '>')
- 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))
- end,
- find = function(in_files)
- ui.find.in_files = in_files
- ui.find.focus()
- end,
- select_command = function() textadept.menu.select_command() end,
- snapopen_filedir = function()
- if buffer.filename then io.snapopen(buffer.filename:match('^(.+)[/\\]')) end
- end,
- show_style = function()
- local pos = buffer.current_pos
- local char = buffer:text_range(pos, buffer:position_after(pos))
- local code = utf8.codepoint(char)
- local bytes = string.rep(' 0x%X', #char):format(char:byte(1, #char))
- local style = buffer.style_at[pos]
- local text = string.format("'%s' (U+%04X:%s)\n%s %s\n%s %s (%d)", char,
- code, bytes, _L['Lexer'], buffer:get_lexer(true),
- _L['Style'], buffer.style_name[style], style)
- buffer:call_tip_show(buffer.current_pos, text)
- end,
- set_indentation = function(i)
- buffer.tab_width = i
- events.emit(events.UPDATE_UI) -- for updating statusbar
- end,
- toggle_property = function(property, i)
- local state = buffer[property]
- if type(state) == 'boolean' then
- buffer[property] = not state
- elseif type(state) == 'number' then
- buffer[property] = state == 0 and (i or 1) or 0
- end
- events.emit(events.UPDATE_UI) -- for updating statusbar
- end,
- set_encoding = function(encoding)
- buffer:set_encoding(encoding)
- events.emit(events.UPDATE_UI) -- for updating statusbar
- end,
- set_eol_mode = function(mode)
- buffer.eol_mode = mode
- buffer:convert_eols(mode)
- events.emit(events.UPDATE_UI) -- for updating statusbar
- end,
- unsplit_all = function() while view:unsplit() do end end,
- grow = function()
- if view.size then view.size = view.size + buffer:text_height(0) end
- end,
- shrink = function()
- if view.size then view.size = view.size - buffer:text_height(0) end
- end,
- toggle_current_fold = function()
- buffer:toggle_fold(buffer:line_from_position(buffer.current_pos))
- end,
- reset_zoom = function() buffer.zoom = 0 end,
- open_webpage = function(url)
- local cmd = 'xdg-open "%s"'
- if WIN32 then
- cmd = 'start "" "%s"'
- elseif OSX then
- cmd = 'open "file://%s"'
- end
- spawn(cmd:format(url))
- end,
- cut_to_eol = function()
- buffer:line_end_extend()
- buffer:cut()
- end
-}
-
-local keys, buffer, view = keys, buffer, view
-local editing, utils = textadept.editing, M.utils
-local OSX, CURSES = OSX, CURSES
-
--- The following buffer functions need to be constantized in order for menu
--- items to identify the key associated with the functions.
-local menu_buffer_functions = {
- 'undo', 'redo', 'cut', 'copy', 'paste', 'line_duplicate', 'clear',
- 'select_all', 'upper_case', 'lower_case', 'move_selected_lines_up',
- 'move_selected_lines_down', 'zoom_in', 'zoom_out', 'colourise'
-}
-for _, f in ipairs(menu_buffer_functions) do buffer[f] = buffer[f] end
-
-- Windows and Linux key bindings.
--
-- Unassigned keys (~ denotes keys reserved by the operating system):
@@ -370,218 +273,228 @@ for _, f in ipairs(menu_buffer_functions) do buffer[f] = buffer[f] end
-- ADD = ''
-- Control, Meta, and 'a' = 'cma'
+local keys, OSX, GUI, CURSES, _L = keys, OSX, not CURSES, CURSES, _L
+
-- File.
-keys[not OSX and (not CURSES and 'cn' or 'cmn') or 'mn'] = buffer.new
+keys[not OSX and (GUI and 'cn' or 'cmn') or 'mn'] = buffer.new
keys[not OSX and 'co' or 'mo'] = io.open_file
-keys[not OSX and not CURSES and 'cao' or 'cmo'] = io.open_recent_file
-keys[not OSX and (not CURSES and 'cO' or 'mo') or 'mO'] = io.reload_file
+keys[not OSX and GUI and 'cao' or 'cmo'] = io.open_recent_file
+keys[not OSX and (GUI and 'cO' or 'mo') or 'mO'] = io.reload_file
keys[not OSX and 'cs' or 'ms'] = io.save_file
-keys[not OSX and (not CURSES and 'cS' or 'cms') or 'mS'] = io.save_file_as
+keys[not OSX and (GUI and 'cS' or 'cms') or 'mS'] = io.save_file_as
-- TODO: io.save_all_files
keys[not OSX and 'cw' or 'mw'] = io.close_buffer
-keys[not OSX and (not CURSES and 'cW' or 'cmw') or 'mW'] = io.close_all_buffers
+keys[not OSX and (GUI and 'cW' or 'cmw') or 'mW'] = io.close_all_buffers
-- TODO: textadept.sessions.load
-- TODO: textadept.sessions.save
keys[not OSX and 'cq' or 'mq'] = quit
-- Edit.
+local m_edit = textadept.menu.menubar[_L['_Edit']]
keys[not OSX and 'cz' or 'mz'] = buffer.undo
if CURSES then keys.mz = keys.cz end -- ^Z suspends in some terminals
if not OSX then keys.cy = buffer.redo end
-keys[not OSX and not CURSES and 'cZ' or 'mZ'] = buffer.redo
+keys[not OSX and GUI and 'cZ' or 'mZ'] = buffer.redo
keys[not OSX and 'cx' or 'mx'] = buffer.cut
keys[not OSX and 'cc' or 'mc'] = buffer.copy
keys[not OSX and 'cv' or 'mv'] = buffer.paste
-if not CURSES then keys[not OSX and 'cd' or 'md'] = buffer.line_duplicate end
+if GUI then keys[not OSX and 'cd' or 'md'] = buffer.line_duplicate end
keys.del = buffer.clear
-keys[not OSX and (not CURSES and 'adel' or 'mdel')
- or 'cdel'] = utils.delete_word
-keys[not OSX and not CURSES and 'ca' or 'ma'] = buffer.select_all
-keys[not CURSES and 'cm' or 'mm'] = editing.match_brace
-keys[not OSX and (not CURSES and 'c\n' or 'cmj')
- or 'cesc'] = {editing.autocomplete, 'word'}
-if CURSES and WIN32 then keys['c\n'] = keys['cmj'] end
-if not CURSES then
- keys[not OSX and 'caH' or 'mH'] = editing.highlight_word
+keys[not OSX and (GUI and 'adel' or 'mdel')
+ or 'cdel'] = m_edit[_L['D_elete Word']][2]
+keys[not OSX and GUI and 'ca' or 'ma'] = buffer.select_all
+keys[GUI and 'cm' or 'mm'] = textadept.editing.match_brace
+keys[not OSX and ((GUI or WIN32) and 'c\n' or 'cmj')
+ or 'cesc'] = m_edit[_L['Complete _Word']][2]
+if GUI then
+ keys[not OSX and 'caH' or 'mH'] = textadept.editing.highlight_word
end
-keys[not OSX and not CURSES and 'c/' or 'm/'] = editing.block_comment
-keys.ct = editing.transpose_chars
-keys[not OSX and (not CURSES and 'cJ' or 'mj') or 'cj'] = editing.join_lines
-keys[not OSX and (not CURSES and 'c|' or 'c\\')
- or 'm|'] = {ui.command_entry.enter_mode, 'filter_through', 'bash'}
+keys[not OSX and GUI and 'c/' or 'm/'] = textadept.editing.block_comment
+keys.ct = textadept.editing.transpose_chars
+keys[not OSX and (GUI and 'cJ' or 'mj') or 'cj'] = textadept.editing.join_lines
+keys[not OSX and (GUI and 'c|' or 'c\\')
+ or 'm|'] = m_edit[_L['_Filter Through']][2]
-- Select.
-keys[not CURSES and 'cM' or 'mM'] = {editing.match_brace, 'select'}
-keys[not OSX and not CURSES and 'c<'
- or 'm<'] = {editing.select_enclosed, '>', '<'}
-if not CURSES then
- keys[not OSX and 'c>' or 'm>'] = {editing.select_enclosed, '<', '>'}
+local m_sel = m_edit[_L['_Select']]
+keys[GUI and 'cM' or 'mM'] = m_sel[_L['Select to _Matching Brace']][2]
+keys[not OSX and GUI and 'c<'
+ or 'm<'] = m_sel[_L['Select between _XML Tags']][2]
+if GUI then
+ keys[not OSX and 'c>' or 'm>'] = m_sel[_L['Select in XML _Tag']][2]
end
-keys[not OSX and not CURSES and "c'"
- or "m'"] = {editing.select_enclosed, "'", "'"}
-keys[not OSX and not CURSES and 'c"'
- or 'm"'] = {editing.select_enclosed, '"', '"'}
-keys[not OSX and not CURSES and 'c('
- or 'm('] = {editing.select_enclosed, '(', ')'}
-keys[not OSX and not CURSES and 'c['
- or 'm['] = {editing.select_enclosed, '[', ']'}
-keys[not OSX and not CURSES and 'c{'
- or 'm{'] = {editing.select_enclosed, '{', '}'}
-keys[not OSX and (not CURSES and 'cD' or 'mW') or 'mD'] = editing.select_word
-keys[not OSX and not CURSES and 'cN' or 'mN'] = editing.select_line
-keys[not OSX and not CURSES and 'cP' or 'mP'] = editing.select_paragraph
+keys[not OSX and GUI and "c'"
+ or "m'"] = m_sel[_L['Select in _Single Quotes']][2]
+keys[not OSX and GUI and 'c"'
+ or 'm"'] = m_sel[_L['Select in _Double Quotes']][2]
+keys[not OSX and GUI and 'c(' or 'm('] = m_sel[_L['Select in _Parentheses']][2]
+keys[not OSX and GUI and 'c[' or 'm['] = m_sel[_L['Select in _Brackets']][2]
+keys[not OSX and GUI and 'c{' or 'm{'] = m_sel[_L['Select in B_races']][2]
+keys[not OSX and (GUI and 'cD' or 'mW') or 'mD'] = textadept.editing.select_word
+keys[not OSX and GUI and 'cN' or 'mN'] = textadept.editing.select_line
+keys[not OSX and GUI and 'cP' or 'mP'] = textadept.editing.select_paragraph
-- Selection.
-keys[not OSX and (not CURSES and 'cau' or 'cmu') or 'cu'] = buffer.upper_case
-keys[not OSX and (not CURSES and 'caU' or 'cml') or 'cU'] = buffer.lower_case
-keys[not OSX and (not CURSES and 'a<' or 'm>')
- or 'c<'] = utils.enclose_as_xml_tags
-if not CURSES then
- keys[not OSX and 'a>' or 'c>'] = {editing.enclose, '<', ' />'}
- keys[not OSX and "a'" or "c'"] = {editing.enclose, "'", "'"}
- keys[not OSX and 'a"' or 'c"'] = {editing.enclose, '"', '"'}
+m_sel = m_edit[_L['Selectio_n']]
+keys[not OSX and (GUI and 'cau' or 'cmu') or 'cu'] = buffer.upper_case
+keys[not OSX and (GUI and 'caU' or 'cml') or 'cU'] = buffer.lower_case
+keys[not OSX and (GUI and 'a<' or 'm>')
+ or 'c<'] = m_sel[_L['Enclose as _XML Tags']][2]
+if GUI then
+ keys[not OSX and 'a>' or 'c>'] = m_sel[_L['Enclose as Single XML _Tag']][2]
+ keys[not OSX and "a'" or "c'"] = m_sel[_L['Enclose in Single _Quotes']][2]
+ keys[not OSX and 'a"' or 'c"'] = m_sel[_L['Enclose in _Double Quotes']][2]
end
-keys[not OSX and (not CURSES and 'a(' or 'm)')
- or 'c('] = {editing.enclose, '(', ')'}
-keys[not OSX and (not CURSES and 'a[' or 'm]')
- or 'c['] = {editing.enclose, '[', ']'}
-keys[not OSX and (not CURSES and 'a{' or 'm}')
- or 'c{'] = {editing.enclose, '{', '}'}
+keys[not OSX and (GUI and 'a(' or 'm)')
+ or 'c('] = m_sel[_L['Enclose in _Parentheses']][2]
+keys[not OSX and (GUI and 'a[' or 'm]')
+ or 'c['] = m_sel[_L['Enclose in _Brackets']][2]
+keys[not OSX and (GUI and 'a{' or 'm}')
+ or 'c{'] = m_sel[_L['Enclose in B_races']][2]
keys.csup = buffer.move_selected_lines_up
keys.csdown = buffer.move_selected_lines_down
-- Search.
-keys[not OSX and not CURSES and 'cf' or 'mf'] = utils.find
-if CURSES then keys.mF = keys.mf end -- in case mf is used by GUI terminals
-keys[not OSX and not CURSES and 'cg' or 'mg'] = ui.find.find_next
-if not OSX and not CURSES then keys.f3 = keys.cg end
-keys[not OSX and not CURSES and 'cG' or 'mG'] = ui.find.find_prev
-if not OSX and not CURSES then keys.sf3 = keys.cG end
-keys[not OSX and (not CURSES and 'car' or 'mr') or 'cr'] = ui.find.replace
-keys[not OSX and (not CURSES and 'caR' or 'mR') or 'cR'] = ui.find.replace_all
+local m_search = textadept.menu.menubar[_L['_Search']]
+keys[not OSX and GUI and 'cf' or 'mf'] = m_search[_L['_Find']][2]
+if CURSES then keys.mF = keys.mf end -- mf is used by some GUI terminals
+keys[not OSX and GUI and 'cg' or 'mg'] = ui.find.find_next
+if not OSX and GUI then keys.f3 = keys.cg end
+keys[not OSX and GUI and 'cG' or 'mG'] = ui.find.find_prev
+if not OSX and GUI then keys.sf3 = keys.cG end
+keys[not OSX and (GUI and 'car' or 'mr') or 'cr'] = ui.find.replace
+keys[not OSX and (GUI and 'caR' or 'mR') or 'cR'] = ui.find.replace_all
-- Find Next is an when find pane is focused in GUI.
-- Find Prev is ap when find pane is focused in GUI.
-- Replace is ar when find pane is focused in GUI.
-- Replace All is aa when find pane is focused in GUI.
-keys[not OSX and not CURSES and 'caf' or 'cmf'] = ui.find.find_incremental
-if not CURSES then keys[not OSX and 'cF' or 'mF'] = {utils.find, true} end
+keys[not OSX and GUI and 'caf' or 'cmf'] = ui.find.find_incremental
+if GUI then
+ keys[not OSX and 'cF' or 'mF'] = m_search[_L['Find in Fi_les']][2]
+end
-- Find in Files is ai when find pane is focused in GUI.
-if not CURSES then
- keys[not OSX and 'cag' or 'cmg'] = {ui.find.goto_file_found, false, true}
- keys[not OSX and 'caG' or 'cmG'] = {ui.find.goto_file_found, false, false}
+if GUI then
+ keys[not OSX and 'cag' or 'cmg'] = m_search[_L['Goto Nex_t File Found']][2]
+ keys[not OSX and 'caG'
+ or 'cmG'] = m_search[_L['Goto Previou_s File Found']][2]
end
-keys[not OSX and 'cj' or 'mj'] = editing.goto_line
+keys[not OSX and 'cj' or 'mj'] = textadept.editing.goto_line
-- Tools.
-keys[not OSX and (not CURSES and 'ce' or 'mc')
- or 'me'] = {ui.command_entry.enter_mode, 'lua_command', 'lua'}
-keys[not OSX and (not CURSES and 'cE' or 'mC') or 'mE'] = utils.select_command
+local m_tools = textadept.menu.menubar[_L['_Tools']]
+keys[not OSX and (GUI and 'ce' or 'mc')
+ or 'me'] = m_tools[_L['Command _Entry']][2]
+keys[not OSX and (GUI and 'cE' or 'mC')
+ or 'mE'] = m_tools[_L['Select Co_mmand']][2]
keys[not OSX and 'cr' or 'mr'] = textadept.run.run
-keys[not OSX and (not CURSES and 'cR' or 'cmr') or 'mR'] = textadept.run.compile
-keys[not OSX and (not CURSES and 'cB' or 'cmb') or 'mB'] = textadept.run.build
-keys[not OSX and (not CURSES and 'cX' or 'cmx') or 'mX'] = textadept.run.stop
-keys[not OSX and (not CURSES and 'cae' or 'mx')
- or 'cme'] = {textadept.run.goto_error, false, true}
-keys[not OSX and (not CURSES and 'caE' or 'mX')
- or 'cmE'] = {textadept.run.goto_error, false, false}
+keys[not OSX and (GUI and 'cR' or 'cmr') or 'mR'] = textadept.run.compile
+keys[not OSX and (GUI and 'cB' or 'cmb') or 'mB'] = textadept.run.build
+keys[not OSX and (GUI and 'cX' or 'cmx') or 'mX'] = textadept.run.stop
+keys[not OSX and (GUI and 'cae' or 'mx')
+ or 'cme'] = m_tools[_L['_Next Error']][2]
+keys[not OSX and (GUI and 'caE' or 'mX')
+ or 'cmE'] = m_tools[_L['_Previous Error']][2]
+-- Bookmark.
+local m_bookmark = m_tools[_L['_Bookmark']]
+keys[not OSX and (GUI and 'cf2' or 'f1') or 'mf2'] = textadept.bookmarks.toggle
+keys[not OSX and (GUI and 'csf2' or 'f6') or 'msf2'] = textadept.bookmarks.clear
+keys.f2 = m_bookmark[_L['_Next Bookmark']][2]
+keys[GUI and 'sf2' or 'f3'] = m_bookmark[_L['_Previous Bookmark']][2]
+keys[GUI and 'af2' or 'f4'] = textadept.bookmarks.goto_mark
+-- Snapopen.
+local m_snapopen = m_tools[_L['Snap_open']]
+keys[not OSX and 'cu' or 'mu'] = m_snapopen[_L['Snapopen _User Home']][2]
+-- TODO: m_snapopen[_L['Snapopen _Textadept Home']][2]
+keys[not OSX and (GUI and 'caO' or 'mO')
+ or 'cmO'] = m_snapopen[_L['Snapopen _Current Directory']][2]
+keys[not OSX and (GUI and 'caP' or 'cmp') or 'cmP'] = io.snapopen
-- Snippets.
-keys[not OSX and (not CURSES and 'ck' or 'mk')
- or 'a\t'] = textadept.snippets._select
+keys[not OSX and (GUI and 'ck' or 'mk') or 'a\t'] = textadept.snippets._select
keys['\t'] = textadept.snippets._insert
keys['s\t'] = textadept.snippets._previous
-keys[not OSX and (not CURSES and 'cK' or 'mK')
+keys[not OSX and (GUI and 'cK' or 'mK')
or 'as\t'] = textadept.snippets._cancel_current
--- Bookmark.
-keys[not OSX and (not CURSES and 'cf2' or 'f1')
- or 'mf2'] = textadept.bookmarks.toggle
-keys[not OSX and (not CURSES and 'csf2' or 'f6')
- or 'msf2'] = textadept.bookmarks.clear
-keys.f2 = {textadept.bookmarks.goto_mark, true}
-keys[not CURSES and 'sf2' or 'f3'] = {textadept.bookmarks.goto_mark, false}
-keys[not CURSES and 'af2' or 'f4'] = textadept.bookmarks.goto_mark
--- Snapopen.
-keys[not OSX and 'cu' or 'mu'] = {io.snapopen, _USERHOME}
--- TODO: {io.snapopen, _HOME}
-keys[not OSX and (not CURSES and 'caO' or 'mO')
- or 'cmO'] = utils.snapopen_filedir
-keys[not OSX and (not CURSES and 'caP' or 'cmp') or 'cmP'] = io.snapopen
-- Other.
-keys[not OSX and ((not CURSES or WIN32) and 'c ' or 'c@')
- or 'aesc'] = utils.autocomplete_symbol
-keys[not CURSES and 'ch' or 'mh'] = textadept.editing.show_documentation
-if CURSES then keys.mH = keys.mh end -- in case mh is used by GUI terminals
-keys[not OSX and (not CURSES and 'ci' or 'mI') or 'mi'] = utils.show_style
+keys[not OSX and ((GUI or WIN32) and 'c ' or 'c@')
+ or 'aesc'] = m_tools[_L['_Complete Symbol']][2]
+keys[GUI and 'ch' or 'mh'] = textadept.editing.show_documentation
+if CURSES then keys.mH = keys.mh end -- mh is used by some GUI terminals
+keys[not OSX and (GUI and 'ci' or 'mI') or 'mi'] = m_tools[_L['Show St_yle']][2]
-- Buffer.
-keys[not CURSES and 'c\t' or 'mn'] = {view.goto_buffer, view, 1, true}
-keys[not CURSES and 'cs\t' or 'mp'] = {view.goto_buffer, view, -1, true}
-keys[not OSX and not CURSES and 'cb' or 'mb'] = ui.switch_buffer
-if CURSES then keys.mB = keys.mb end -- in case mb is used by GUI terminals
+local m_buffer = textadept.menu.menubar[_L['_Buffer']]
+keys[GUI and 'c\t' or 'mn'] = m_buffer[_L['_Next Buffer']][2]
+keys[GUI and 'cs\t' or 'mp'] = m_buffer[_L['_Previous Buffer']][2]
+keys[not OSX and GUI and 'cb' or 'mb'] = ui.switch_buffer
+if CURSES then keys.mB = keys.mb end -- mb is used by some GUI terminals
-- Indentation.
--- TODO: {utils.set_indentation, 2}
--- TODO: {utils.set_indentation, 3}
--- TODO: {utils.set_indentation, 4}
--- TODO: {utils.set_indentation, 8}
-keys[not OSX and (not CURSES and 'caT' or 'mt')
- or 'cT'] = {utils.toggle_property, 'use_tabs'}
-if CURSES then keys.mT = keys.mt end -- in case mt is used by GUI terminals
-keys[not OSX and (not CURSES and 'cai' or 'mi')
- or 'ci'] = editing.convert_indentation
+local m_indentation = m_buffer[_L['_Indentation']]
+-- TODO: m_indentation[_L['Tab width: _2']][2]
+-- TODO: m_indentation[_L['Tab width: _3']][2]
+-- TODO: m_indentation[_L['Tab width: _4']][2]
+-- TODO: m_indentation[_L['Tab width: _8']][2]
+keys[not OSX and (GUI and 'caT' or 'mt')
+ or 'cT'] = m_indentation[_L['_Toggle Use Tabs']][2]
+if CURSES then keys.mT = keys.mt end -- mt is used by some GUI terminals
+keys[not OSX and (GUI and 'cai' or 'mi')
+ or 'ci'] = textadept.editing.convert_indentation
-- EOL Mode.
--- TODO: {utils.set_eol_mode, buffer.EOL_CRLF}
--- TODO: {utils.set_eol_mode, buffer.EOL_CR}
--- TODO: {utils.set_eol_mode, buffer.EOL_LF}
+-- TODO: m_buffer[_L['_EOL Mode']][_L['CRLF']][2]
+-- TODO: m_buffer[_L['_EOL Mode']][_L['CR']][2]
+-- TODO: m_buffer[_L['_EOL Mode']][_L['LF']][2]
-- Encoding.
--- TODO: {utils.set_encoding, 'UTF-8'}
--- TODO: {utils.set_encoding, 'ASCII'}
--- TODO: {utils.set_encoding, 'ISO-8859-1'}
--- TODO: {utils.set_encoding, 'MacRoman'}
--- TODO: {utils.set_encoding, 'UTF-16LE'}
-keys[not OSX and not CURSES and 'cL'
- or 'mL'] = textadept.file_types.select_lexer
-keys.f5 = {buffer.colourise, buffer, 0, -1}
+-- TODO: m_buffer[_L['E_ncoding']][_L['_UTF-8 Encoding']][2]
+-- TODO: m_buffer[_L['E_ncoding']][_L['_ASCII Encoding']][2]
+-- TODO: m_buffer[_L['E_ncoding']][_L['_ISO-8859-1 Encoding']][2]
+-- TODO: m_buffer[_L['E_ncoding']][_L['_MacRoman Encoding']][2]
+-- TODO: m_buffer[_L['E_ncoding']][_L['UTF-1_6 Encoding']][2]
+if GUI then
+ keys[not OSX and 'ca\n' or 'c\n'] = m_buffer[_L['Toggle View _EOL']][2]
+ keys[not OSX and 'ca\\' or 'c\\'] = m_buffer[_L['Toggle _Wrap Mode']][2]
+ keys[not OSX and 'caS' or 'cS'] = m_buffer[_L['Toggle View White_space']][2]
+end
+keys[not OSX and GUI and 'cL' or 'mL'] = textadept.file_types.select_lexer
+keys.f5 = m_buffer[_L['_Refresh Syntax Highlighting']][2]
if CURSES then keys.cl = keys.f5 end
-- View.
-local view_next, view_prev = {ui.goto_view, 1, true}, {ui.goto_view, -1, true}
-local view_splith, view_splitv = {view.split, view}, {view.split, view, true}
-local view_unsplit = {view.unsplit, view}
-if not CURSES then
- keys[not OSX and 'can' or 'ca\t'] = view_next
- keys[not OSX and 'cap' or 'cas\t'] = view_prev
- keys[not OSX and 'cas' or 'cs'] = view_splith
- if not OSX then keys.cah = view_splith end
- keys[not OSX and 'cav' or 'cv'] = view_splitv
- keys[not OSX and 'caw' or 'cw'] = view_unsplit
- keys[not OSX and 'caW' or 'cW'] = utils.unsplit_all
- keys[not OSX and 'ca+' or 'c+'] = utils.grow
- keys[not OSX and 'ca=' or 'c='] = utils.grow
- keys[not OSX and 'ca-' or 'c-'] = utils.shrink
+local m_view = textadept.menu.menubar[_L['_View']]
+if GUI then
+ keys[not OSX and 'can' or 'ca\t'] = m_view[_L['_Next View']][2]
+ keys[not OSX and 'cap' or 'cas\t'] = m_view[_L['_Previous View']][2]
+ keys[not OSX and 'cas' or 'cs'] = m_view[_L['Split View _Horizontal']][2]
+ if not OSX then keys.cah = keys.cas end
+ keys[not OSX and 'cav' or 'cv'] = m_view[_L['Split View _Vertical']][2]
+ keys[not OSX and 'caw' or 'cw'] = m_view[_L['_Unsplit View']][2]
+ keys[not OSX and 'caW' or 'cW'] = m_view[_L['Unsplit _All Views']][2]
+ keys[not OSX and 'ca+' or 'c+'] = m_view[_L['_Grow View']][2]
+ keys[not OSX and 'ca=' or 'c='] = keys[not OSX and 'ca+' or 'c+']
+ keys[not OSX and 'ca-' or 'c-'] = m_view[_L['Shrin_k View']][2]
else
keys.cmv = {
- n = view_next, p = view_prev,
- s = view_splith, v = view_splitv,
- w = view_unsplit, W = utils.unsplit_all,
- ['+'] = utils.grow, ['='] = utils.grow, ['-'] = utils.shrink
+ n = m_view[_L['_Next View']][2],
+ p = m_view[_L['_Previous View']][2],
+ s = m_view[_L['Split View _Horizontal']][2],
+ v = m_view[_L['Split View _Vertical']][2],
+ w = m_view[_L['_Unsplit View']][2],
+ W = m_view[_L['Unsplit _All Views']][2],
+ ['+'] = m_view[_L['_Grow View']][2],
+ ['-'] = m_view[_L['Shrin_k View']][2]
}
- if not OSX then keys.cmv.h = view_splith end
+ if not OSX then keys.cmv.h = keys.cmv.s end
+ keys.cmv['='] = keys.cmv['+']
end
-keys[not OSX and not CURSES and 'c*' or 'm*'] = utils.toggle_current_fold
-if not CURSES then
- keys[not OSX and 'ca\n' or 'c\n'] = {utils.toggle_property, 'view_eol'}
- keys[not OSX and 'ca\\' or 'c\\'] = {utils.toggle_property, 'wrap_mode'}
- keys[not OSX and 'caI' or 'cI'] =
- {utils.toggle_property, 'indentation_guides'}
- keys[not OSX and 'caS' or 'cS'] = {utils.toggle_property, 'view_ws'}
- keys[not OSX and 'caV' or 'cV'] =
- {utils.toggle_property, 'virtual_space_options', buffer.VS_USERACCESSIBLE}
+keys[not OSX and GUI and 'c*' or 'm*'] = m_view[_L['Toggle Current _Fold']][2]
+if GUI then
+ keys[not OSX and 'caI' or 'cI'] = m_view[_L['Toggle Show In_dent Guides']][2]
+ keys[not OSX and 'caV' or 'cV'] = m_view[_L['Toggle _Virtual Space']][2]
end
-keys[not OSX and not CURSES and 'c=' or 'm='] = buffer.zoom_in
-keys[not OSX and not CURSES and 'c-' or 'm-'] = buffer.zoom_out
-keys[not OSX and not CURSES and 'c0' or 'm0'] = utils.reset_zoom
+keys[not OSX and GUI and 'c=' or 'm='] = buffer.zoom_in
+keys[not OSX and GUI and 'c-' or 'm-'] = buffer.zoom_out
+keys[not OSX and GUI and 'c0' or 'm0'] = m_view[_L['_Reset Zoom']][2]
-- Help.
-if not CURSES then
- keys.f1 = {utils.open_webpage, _HOME..'/doc/manual.html'}
- keys.sf1 = {utils.open_webpage, _HOME..'/doc/api.html'}
+if GUI then
+ keys.f1 = textadept.menu.menubar[_L['_Help']][_L['Show _Manual']][2]
+ keys.sf1 = textadept.menu.menubar[_L['_Help']][_L['Show _LuaDoc']][2]
end
-- Movement commands.
@@ -596,13 +509,16 @@ if OSX then
keys.ce, keys.cE = buffer.line_end, buffer.line_end_extend
keys.aright, keys.aleft = buffer.word_right, buffer.word_left
keys.cd = buffer.clear
- keys.ck = utils.cut_to_eol
+ keys.ck = function()
+ buffer:line_end_extend()
+ buffer:cut()
+ end
keys.cl = buffer.vertical_centre_caret
- -- GTKOSX reports Fn-key as a single keycode which confuses Scintilla. Do
+ -- GTK-OSX reports Fn-key as a single keycode which confuses Scintilla. Do
-- not propagate it.
keys.fn = function() return true end
elseif CURSES then
- keys['c^'] = function() _G.buffer.selection_mode = 0 end
+ keys['c^'] = function() buffer.selection_mode = 0 end
keys['c]'] = buffer.swap_main_anchor_caret
keys.cf, keys.cb = buffer.char_right, buffer.char_left
keys.cn, keys.cp = buffer.line_down, buffer.line_up
@@ -610,13 +526,18 @@ elseif CURSES then
keys.mA, keys.mE = buffer.vc_home_extend, buffer.line_end_extend
keys.mU, keys.mD = buffer.page_up_extend, buffer.page_down_extend
keys.cma, keys.cme = buffer.document_start, buffer.document_end
- keys.cd, keys.md = buffer.clear, utils.delete_word
- keys.ck = utils.cut_to_eol
+ keys.cd, keys.md = buffer.clear, keys.mdel
+ keys.ck = function()
+ buffer:line_end_extend()
+ buffer:cut()
+ end
end
-- Modes.
keys.filter_through = {
- ['\n'] = {ui.command_entry.finish_mode, editing.filter_through},
+ ['\n'] = function()
+ return ui.command_entry.finish_mode(textadept.editing.filter_through)
+ end,
}
keys.find_incremental = {
['\n'] = function()
@@ -638,7 +559,7 @@ setmetatable(keys.find_incremental, {__index = function(_, k)
ui.find.find_incremental(ui.command_entry:get_text()..k, true)
end})
-- Show documentation for symbols in the Lua command entry.
-keys.lua_command[not CURSES and 'ch' or 'mh'] = function()
+keys.lua_command[GUI and 'ch' or 'mh'] = function()
-- Temporarily change _G.buffer since ui.command_entry is the "active" buffer.
local orig_buffer = _G.buffer
_G.buffer = ui.command_entry
@@ -647,10 +568,16 @@ keys.lua_command[not CURSES and 'ch' or 'mh'] = function()
end
if OSX or CURSES then
-- UTF-8 input.
- keys.utf8_input = {['\n'] = {ui.command_entry.finish_mode, function(code)
- _G.buffer:add_text(utf8.char(tonumber(code, 16)))
- end}}
- keys[OSX and 'mU' or 'mu'] = {ui.command_entry.enter_mode, 'utf8_input'}
+ keys.utf8_input = {
+ ['\n'] = function()
+ return ui.command_entry.finish_mode(function(code)
+ buffer:add_text(utf8.char(tonumber(code, 16)))
+ end)
+ end
+ }
+ keys[OSX and 'mU' or 'mu'] = function()
+ ui.command_entry.enter_mode('utf8_input')
+ end
end
return M
diff --git a/modules/textadept/menu.lua b/modules/textadept/menu.lua
index f2bd2d17..acec62b3 100644
--- a/modules/textadept/menu.lua
+++ b/modules/textadept/menu.lua
@@ -10,25 +10,54 @@ local M = {}
-- place. A menu item itself is a table whose first element is a menu label and
-- whose second element is a menu command to run. Submenus have `title` keys
-- assigned to string text.
--- If applicable, load this module last in your *~/.textadept/init.lua*, after
--- [`textadept.keys`]() since it looks up defined key commands to show them in
--- menus.
module('textadept.menu')]]
-local _L, buffer, view = _L, buffer, view
-local editing, utils = textadept.editing, textadept.keys.utils
+local _L = _L
local SEPARATOR = {''}
+-- The following buffer functions need to be constantized in order for menu
+-- items to identify the key associated with the functions.
+local menu_buffer_functions = {
+ 'undo', 'redo', 'cut', 'copy', 'paste', 'line_duplicate', 'clear',
+ 'select_all', 'upper_case', 'lower_case', 'move_selected_lines_up',
+ 'move_selected_lines_down', 'zoom_in', 'zoom_out', 'colourise'
+}
+for i = 1, #menu_buffer_functions do
+ buffer[menu_buffer_functions[i]] = buffer[menu_buffer_functions[i]]
+end
+
+-- Commonly used functions in menu commands.
+local sel_enc = textadept.editing.select_enclosed
+local enc = textadept.editing.enclose
+local function set_indentation(i)
+ buffer.tab_width = i
+ events.emit(events.UPDATE_UI) -- for updating statusbar
+end
+local function set_eol_mode(mode)
+ buffer.eol_mode = mode
+ buffer:convert_eols(mode)
+ events.emit(events.UPDATE_UI) -- for updating statusbar
+end
+local function set_encoding(encoding)
+ buffer:set_encoding(encoding)
+ events.emit(events.UPDATE_UI) -- for updating statusbar
+end
+local function open_page(url)
+ local cmd = (WIN32 and 'start ""') or (OSX and 'open') or 'xdg-open'
+ spawn(string.format('%s "%s"', cmd, not OSX and url or 'file://'..url))
+end
+
---
-- The default main menubar.
-- Individual menus, submenus, and menu items can be retrieved by name in
-- addition to table index number.
-- @class table
-- @name menubar
--- @usage textadept.menubar[_L['_File']]['_New'] -- returns {'_New', buffer.new}
--- @usage textadept.menubar[_L['_File']]['_New'][2] = function() ... end
+-- @usage textadept.menu.menubar[_L['_File']][_L['_New']]
+-- @usage textadept.menu.menubar[_L['_File']][_L['_New']][2] = function() .. end
local default_menubar = {
- { title = _L['_File'],
+ {
+ title = _L['_File'],
{_L['_New'], buffer.new},
{_L['_Open'], io.open_file},
{_L['Open _Recent...'], io.open_recent_file},
@@ -43,9 +72,10 @@ local default_menubar = {
{_L['Loa_d Session...'], textadept.session.load},
{_L['Sav_e Session...'], textadept.session.save},
SEPARATOR,
- {_L['_Quit'], quit},
+ {_L['_Quit'], quit}
},
- { title = _L['_Edit'],
+ {
+ title = _L['_Edit'],
{_L['_Undo'], buffer.undo},
{_L['_Redo'], buffer.redo},
SEPARATOR,
@@ -54,161 +84,241 @@ local default_menubar = {
{_L['_Paste'], buffer.paste},
{_L['Duplicate _Line'], buffer.line_duplicate},
{_L['_Delete'], buffer.clear},
- {_L['D_elete Word'], utils.delete_word},
+ {_L['D_elete Word'], function()
+ textadept.editing.select_word()
+ buffer:delete_back()
+ end},
{_L['Select _All'], buffer.select_all},
SEPARATOR,
- {_L['_Match Brace'], editing.match_brace},
- {_L['Complete _Word'], {editing.autocomplete, 'word'}},
- {_L['_Highlight Word'], editing.highlight_word},
- {_L['Toggle _Block Comment'], editing.block_comment},
- {_L['T_ranspose Characters'], editing.transpose_chars},
- {_L['_Join Lines'], editing.join_lines},
- {_L['_Filter Through'],
- {ui.command_entry.enter_mode, 'filter_through', 'bash'}},
- { title = _L['_Select'],
- {_L['Select to _Matching Brace'], {editing.match_brace, 'select'}},
- {_L['Select between _XML Tags'], {editing.select_enclosed, '>', '<'}},
- {_L['Select in XML _Tag'], {editing.select_enclosed, '<', '>'}},
- {_L['Select in _Single Quotes'], {editing.select_enclosed, "'", "'"}},
- {_L['Select in _Double Quotes'], {editing.select_enclosed, '"', '"'}},
- {_L['Select in _Parentheses'], {editing.select_enclosed, '(', ')'}},
- {_L['Select in _Brackets'], {editing.select_enclosed, '[', ']'}},
- {_L['Select in B_races'], {editing.select_enclosed, '{', '}'}},
- {_L['Select _Word'], editing.select_word},
- {_L['Select _Line'], editing.select_line},
- {_L['Select Para_graph'], editing.select_paragraph},
+ {_L['_Match Brace'], textadept.editing.match_brace},
+ {_L['Complete _Word'], function()
+ textadept.editing.autocomplete('word')
+ end},
+ {_L['_Highlight Word'], textadept.editing.highlight_word},
+ {_L['Toggle _Block Comment'], textadept.editing.block_comment},
+ {_L['T_ranspose Characters'], textadept.editing.transpose_chars},
+ {_L['_Join Lines'], textadept.editing.join_lines},
+ {_L['_Filter Through'], function()
+ ui.command_entry.enter_mode('filter_through', 'bash')
+ end},
+ {
+ title = _L['_Select'],
+ {_L['Select to _Matching Brace'], function()
+ textadept.editing.match_brace('select')
+ end},
+ {_L['Select between _XML Tags'], function() sel_enc('>', '<') end},
+ {_L['Select in XML _Tag'], function() sel_enc('<', '>') end},
+ {_L['Select in _Single Quotes'], function() sel_enc("'", "'") end},
+ {_L['Select in _Double Quotes'], function() sel_enc('"', '"') end},
+ {_L['Select in _Parentheses'], function() sel_enc('(', ')') end},
+ {_L['Select in _Brackets'], function() sel_enc('[', ']') end},
+ {_L['Select in B_races'], function() sel_enc('{', '}') end},
+ {_L['Select _Word'], textadept.editing.select_word},
+ {_L['Select _Line'], textadept.editing.select_line},
+ {_L['Select Para_graph'], textadept.editing.select_paragraph}
},
- { title = _L['Selectio_n'],
+ {
+ title = _L['Selectio_n'],
{_L['_Upper Case Selection'], buffer.upper_case},
{_L['_Lower Case Selection'], buffer.lower_case},
SEPARATOR,
- {_L['Enclose as _XML Tags'], utils.enclose_as_xml_tags},
- {_L['Enclose as Single XML _Tag'], {editing.enclose, '<', ' />'}},
- {_L['Enclose in Single _Quotes'], {editing.enclose, "'", "'"}},
- {_L['Enclose in _Double Quotes'], {editing.enclose, '"', '"'}},
- {_L['Enclose in _Parentheses'], {editing.enclose, '(', ')'}},
- {_L['Enclose in _Brackets'], {editing.enclose, '[', ']'}},
- {_L['Enclose in B_races'], {editing.enclose, '{', '}'}},
+ {_L['Enclose as _XML Tags'], function()
+ 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))
+ end},
+ {_L['Enclose as Single XML _Tag'], function() enc('<', ' />') end},
+ {_L['Enclose in Single _Quotes'], function() enc("'", "'") end},
+ {_L['Enclose in _Double Quotes'], function() enc('"', '"') end},
+ {_L['Enclose in _Parentheses'], function() enc('(', ')') end},
+ {_L['Enclose in _Brackets'], function() enc('[', ']') end},
+ {_L['Enclose in B_races'], function() enc('{', '}') end},
SEPARATOR,
{_L['_Move Selected Lines Up'], buffer.move_selected_lines_up},
- {_L['Move Selected Lines Do_wn'], buffer.move_selected_lines_down},
- },
+ {_L['Move Selected Lines Do_wn'], buffer.move_selected_lines_down}
+ }
},
- { title = _L['_Search'],
- {_L['_Find'], utils.find},
+ {
+ title = _L['_Search'],
+ {_L['_Find'], function()
+ ui.find.in_files = false
+ ui.find.focus()
+ end},
{_L['Find _Next'], ui.find.find_next},
{_L['Find _Previous'], ui.find.find_prev},
{_L['_Replace'], ui.find.replace},
{_L['Replace _All'], ui.find.replace_all},
{_L['Find _Incremental'], ui.find.find_incremental},
SEPARATOR,
- {_L['Find in Fi_les'], {utils.find, true}},
- {_L['Goto Nex_t File Found'], {ui.find.goto_file_found, false, true}},
- {_L['Goto Previou_s File Found'], {ui.find.goto_file_found, false, false}},
+ {_L['Find in Fi_les'], function()
+ ui.find.in_files = true
+ ui.find.focus()
+ end},
+ {_L['Goto Nex_t File Found'], function()
+ ui.find.goto_file_found(false, true)
+ end},
+ {_L['Goto Previou_s File Found'], function()
+ ui.find.goto_file_found(false, false)
+ end},
SEPARATOR,
- {_L['_Jump to'], editing.goto_line},
+ {_L['_Jump to'], textadept.editing.goto_line}
},
- { title = _L['_Tools'],
- {_L['Command _Entry'], {ui.command_entry.enter_mode, 'lua_command', 'lua'}},
- {_L['Select Co_mmand'], utils.select_command},
+ {
+ title = _L['_Tools'],
+ {_L['Command _Entry'], function()
+ ui.command_entry.enter_mode('lua_command', 'lua')
+ end},
+ {_L['Select Co_mmand'], function() M.select_command() end},
SEPARATOR,
{_L['_Run'], textadept.run.run},
{_L['_Compile'], textadept.run.compile},
{_L['Buil_d'], textadept.run.build},
{_L['S_top'], textadept.run.stop},
- {_L['_Next Error'], {textadept.run.goto_error, false, true}},
- {_L['_Previous Error'], {textadept.run.goto_error, false, false}},
+ {_L['_Next Error'], function() textadept.run.goto_error(false, true) end},
+ {_L['_Previous Error'], function()
+ textadept.run.goto_error(false, false)
+ end},
SEPARATOR,
- { title = _L['_Bookmark'],
+ {
+ title = _L['_Bookmark'],
{_L['_Toggle Bookmark'], textadept.bookmarks.toggle},
{_L['_Clear Bookmarks'], textadept.bookmarks.clear},
- {_L['_Next Bookmark'], {textadept.bookmarks.goto_mark, true}},
- {_L['_Previous Bookmark'], {textadept.bookmarks.goto_mark, false}},
+ {_L['_Next Bookmark'], function()
+ textadept.bookmarks.goto_mark(true)
+ end},
+ {_L['_Previous Bookmark'], function()
+ textadept.bookmarks.goto_mark(false)
+ end},
{_L['_Goto Bookmark...'], textadept.bookmarks.goto_mark},
},
- { title = _L['Snap_open'],
- {_L['Snapopen _User Home'], {io.snapopen, _USERHOME}},
- {_L['Snapopen _Textadept Home'], {io.snapopen, _HOME}},
- {_L['Snapopen _Current Directory'], utils.snapopen_filedir},
+ {
+ title = _L['Snap_open'],
+ {_L['Snapopen _User Home'], function() io.snapopen(_USERHOME) end},
+ {_L['Snapopen _Textadept Home'], function() io.snapopen(_HOME) end},
+ {_L['Snapopen _Current Directory'], function()
+ if buffer.filename then
+ io.snapopen(buffer.filename:match('^(.+)[/\\]'))
+ end
+ end},
{_L['Snapopen Current _Project'], io.snapopen},
},
- { title = _L['_Snippets'],
+ {
+ title = _L['_Snippets'],
{_L['_Insert Snippet...'], textadept.snippets._select},
{_L['_Expand Snippet/Next Placeholder'], textadept.snippets._insert},
{_L['_Previous Snippet Placeholder'], textadept.snippets._previous},
{_L['_Cancel Snippet'], textadept.snippets._cancel_current},
},
SEPARATOR,
- {_L['_Complete Symbol'], utils.autocomplete_symbol},
+ {_L['_Complete Symbol'], function()
+ textadept.editing.autocomplete(buffer:get_lexer(true))
+ end},
{_L['Show _Documentation'], textadept.editing.show_documentation},
- {_L['Show St_yle'], utils.show_style},
+ {_L['Show St_yle'], function()
+ local char = buffer:text_range(buffer.current_pos,
+ buffer:position_after(buffer.current_pos))
+ 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.style_name[style], style)
+ buffer:call_tip_show(buffer.current_pos, text)
+ end}
},
- { title = _L['_Buffer'],
- {_L['_Next Buffer'], {view.goto_buffer, view, 1, true}},
- {_L['_Previous Buffer'], {view.goto_buffer, view, -1, true}},
+ {
+ title = _L['_Buffer'],
+ {_L['_Next Buffer'], function() view:goto_buffer(1, true) end},
+ {_L['_Previous Buffer'], function() view:goto_buffer(-1, true) end},
{_L['_Switch to Buffer...'], ui.switch_buffer},
SEPARATOR,
- { title = _L['_Indentation'],
- {_L['Tab width: _2'], {utils.set_indentation, 2}},
- {_L['Tab width: _3'], {utils.set_indentation, 3}},
- {_L['Tab width: _4'], {utils.set_indentation, 4}},
- {_L['Tab width: _8'], {utils.set_indentation, 8}},
+ {
+ title = _L['_Indentation'],
+ {_L['Tab width: _2'], function() set_indentation(2) end},
+ {_L['Tab width: _3'], function() set_indentation(3) end},
+ {_L['Tab width: _4'], function() set_indentation(4) end},
+ {_L['Tab width: _8'], function() set_indentation(8) end},
SEPARATOR,
- {_L['_Toggle Use Tabs'], {utils.toggle_property, 'use_tabs'}},
- {_L['_Convert Indentation'], editing.convert_indentation},
+ {_L['_Toggle Use Tabs'], function()
+ buffer.use_tabs = not buffer.use_tabs
+ events.emit(events.UPDATE_UI) -- for updating statusbar
+ end},
+ {_L['_Convert Indentation'], textadept.editing.convert_indentation}
},
- { title = _L['_EOL Mode'],
- {_L['CRLF'], {utils.set_eol_mode, buffer.EOL_CRLF}},
- {_L['CR'], {utils.set_eol_mode, buffer.EOL_CR}},
- {_L['LF'], {utils.set_eol_mode, buffer.EOL_LF}},
+ {
+ title = _L['_EOL Mode'],
+ {_L['CRLF'], function() set_eol_mode(buffer.EOL_CRLF) end},
+ {_L['CR'], function() set_eol_mode(buffer.EOL_CR) end},
+ {_L['LF'], function() set_eol_mode(buffer.EOL_LF) end}
},
- { title = _L['E_ncoding'],
- {_L['_UTF-8 Encoding'], {utils.set_encoding, 'UTF-8'}},
- {_L['_ASCII Encoding'], {utils.set_encoding, 'ASCII'}},
- {_L['_ISO-8859-1 Encoding'], {utils.set_encoding, 'ISO-8859-1'}},
- {_L['_MacRoman Encoding'], {utils.set_encoding, 'MacRoman'}},
- {_L['UTF-1_6 Encoding'], {utils.set_encoding, 'UTF-16LE'}},
+ {
+ title = _L['E_ncoding'],
+ {_L['_UTF-8 Encoding'], function() set_encoding('UTF-8') end},
+ {_L['_ASCII Encoding'], function() set_encoding('ASCII') end},
+ {_L['_ISO-8859-1 Encoding'], function() set_encoding('ISO-8859-1') end},
+ {_L['_MacRoman Encoding'], function() set_encoding('MacRoman') end},
+ {_L['UTF-1_6 Encoding'], function() set_encoding('UTF-16LE') end}
},
SEPARATOR,
- {_L['Toggle View _EOL'], {utils.toggle_property, 'view_eol'}},
- {_L['Toggle _Wrap Mode'], {utils.toggle_property, 'wrap_mode'}},
- {_L['Toggle View White_space'], {utils.toggle_property, 'view_ws'}},
+ {_L['Toggle View _EOL'], function()
+ buffer.view_eol = not buffer.view_eol
+ end},
+ {_L['Toggle _Wrap Mode'], function()
+ buffer.wrap_mode = buffer.wrap_mode == 0 and buffer.WRAP_WHITESPACE or 0
+ end},
+ {_L['Toggle View White_space'], function()
+ buffer.view_ws = buffer.view_ws == 0 and buffer.WS_VISIBLEALWAYS or 0
+ end},
SEPARATOR,
{_L['Select _Lexer...'], textadept.file_types.select_lexer},
- {_L['_Refresh Syntax Highlighting'], {buffer.colourise, buffer, 0, -1}},
+ {_L['_Refresh Syntax Highlighting'], function() buffer:colourise(0, -1) end}
},
- { title = _L['_View'],
- {_L['_Next View'], {ui.goto_view, 1, true}},
- {_L['_Previous View'], {ui.goto_view, -1, true}},
+ {
+ title = _L['_View'],
+ {_L['_Next View'], function() ui.goto_view(1, true) end},
+ {_L['_Previous View'], function() ui.goto_view(-1, true) end},
SEPARATOR,
- {_L['Split View _Horizontal'], {view.split, view}},
- {_L['Split View _Vertical'], {view.split, view, true}},
- {_L['_Unsplit View'], {view.unsplit, view}},
- {_L['Unsplit _All Views'], utils.unsplit_all},
- {_L['_Grow View'], utils.grow},
- {_L['Shrin_k View'], utils.shrink},
+ {_L['Split View _Horizontal'], function() view:split() end},
+ {_L['Split View _Vertical'], function() view:split(true) end},
+ {_L['_Unsplit View'], function() view:unsplit() end},
+ {_L['Unsplit _All Views'], function() while view:unsplit() do end end},
+ {_L['_Grow View'], function()
+ if view.size then view.size = view.size + buffer:text_height(0) end
+ end},
+ {_L['Shrin_k View'], function()
+ if view.size then view.size = view.size - buffer:text_height(0) end
+ end},
SEPARATOR,
- {_L['Toggle Current _Fold'], utils.toggle_current_fold},
+ {_L['Toggle Current _Fold'], function()
+ buffer:toggle_fold(buffer:line_from_position(buffer.current_pos))
+ end},
SEPARATOR,
- {_L['Toggle Show In_dent Guides'],
- {utils.toggle_property, 'indentation_guides'}},
- {_L['Toggle _Virtual Space'],
- {utils.toggle_property, 'virtual_space_options',
- buffer.VS_USERACCESSIBLE}},
+ {_L['Toggle Show In_dent Guides'], function()
+ local off = buffer.indentation_guides == 0
+ buffer.indentation_guides = off and buffer.IV_LOOKBOTH or 0
+ end},
+ {_L['Toggle _Virtual Space'], function()
+ local off = buffer.virtual_space_options == 0
+ buffer.virtual_space_options = off and buffer.VS_USERACCESSIBLE or 0
+ end},
SEPARATOR,
{_L['Zoom _In'], buffer.zoom_in},
{_L['Zoom _Out'], buffer.zoom_out},
- {_L['_Reset Zoom'], utils.reset_zoom},
+ {_L['_Reset Zoom'], function() buffer.zoom = 0 end}
},
- { title = _L['_Help'],
- {_L['Show _Manual'], {utils.open_webpage, _HOME..'/doc/manual.html'}},
- {_L['Show _LuaDoc'], {utils.open_webpage, _HOME..'/doc/api.html'}},
+ {
+ 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},
SEPARATOR,
- {_L['_About'],
- {ui.dialogs.msgbox, {title = 'Textadept', text = _RELEASE,
- informative_text = _COPYRIGHT,
- icon_file = _HOME..'/core/images/ta_64x64.png'}}},
- },
+ {_L['_About'], function()
+ ui.dialogs.msgbox({
+ title = 'Textadept', text = _RELEASE, informative_text = _COPYRIGHT,
+ icon_file = _HOME..'/core/images/ta_64x64.png'
+ })
+ end}
+ }
}
---
@@ -311,27 +421,6 @@ local function read_menu_table(menu, contextmenu)
return gtkmenu
end
--- Builds the item and commands tables for the filtered list dialog.
--- @param menu The menu to read from.
--- @param title The title of the menu.
--- @param items The current list of items.
--- @param commands The current list of commands.
-local function build_command_tables(menu, title, items, commands)
- for i = 1, #menu do
- if menu[i].title then
- build_command_tables(menu[i], menu[i].title, items, commands)
- elseif menu[i][1] ~= '' then
- local label, f = menu[i][1], menu[i][2]
- if title then label = title..': '..label end
- items[#items + 1] = label:gsub('_([^_])', '%1')
- items[#items + 1] = key_shortcuts[get_id(f)] or ''
- commands[#commands + 1] = f
- end
- end
-end
-
-local items, commands
-
-- Returns a proxy table for menu table *menu* such that when a menu item is
-- changed or added, *update* is called to update the menu in the UI.
-- @param menu The menu or table of menus to create a proxy for.
@@ -343,7 +432,7 @@ local function proxy_menu(menu, update, menubar)
return setmetatable({}, {
__index = function(_, k)
local v
- if type(k) == 'number' then
+ if type(k) == 'number' or k == 'title' then
v = menu[k]
elseif type(k) == 'string' then
for i = 1, #menu do
@@ -378,11 +467,10 @@ local function set_menubar(menubar)
_menubar[#_menubar + 1] = ui.menu(read_menu_table(menubar[i]))
end
ui.menubar = _menubar
- items, commands = {}, {}
- build_command_tables(menubar, nil, items, commands)
proxies.menubar = proxy_menu(menubar, set_menubar)
end
-set_menubar(default_menubar)
+proxies.menubar = proxy_menu(default_menubar, function() end) -- for keys.lua
+events.connect(events.INITIALIZED, function() set_menubar(default_menubar) end)
-- Sets `ui.context_menu` and `ui.tab_context_menu` from menu item lists
-- *buffer_menu* and *tab_menu*, respectively.
@@ -408,12 +496,37 @@ local function set_contextmenus(buffer_menu, tab_menu)
set_contextmenus(nil, menu)
end)
end
-set_contextmenus()
+events.connect(events.INITIALIZED, set_contextmenus)
+
+-- Performs the appropriate action when clicking a menu item.
+events.connect(events.MENU_CLICKED, function(menu_id)
+ local actions = menu_id < 1000 and menu_actions or contextmenu_actions
+ local action = actions[menu_id < 1000 and menu_id or menu_id - 1000]
+ assert(type(action) == 'function' or type(action) == 'table',
+ _L['Unknown command:']..' '..tostring(action))
+ keys.run_command(action, type(action))
+end)
---
-- Prompts the user to select a menu command to run.
-- @name select_command
function M.select_command()
+ local items, commands = {}, {}
+ -- Builds the item and commands 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]
+ items[#items + 1] = label:gsub('_([^_])', '%1')
+ items[#items + 1] = key_shortcuts[get_id(menu[i][2])] or ''
+ commands[#commands + 1] = menu[i][2]
+ end
+ end
+ end
+ build_command_tables(getmetatable(M.menubar).menu)
local button, i = ui.dialogs.filteredlist{
title = _L['Run Command'], columns = {_L['Command'], _L['Key Command']},
items = items, width = CURSES and ui.size[1] - 2 or nil
@@ -422,15 +535,6 @@ function M.select_command()
keys.run_command(commands[i], type(commands[i]))
end
--- Performs the appropriate action when clicking a menu item.
-events.connect(events.MENU_CLICKED, function(menu_id)
- local actions = menu_id < 1000 and menu_actions or contextmenu_actions
- local action = actions[menu_id < 1000 and menu_id or menu_id - 1000]
- assert(type(action) == 'function' or type(action) == 'table',
- _L['Unknown command:']..' '..tostring(action))
- keys.run_command(action, type(action))
-end)
-
return setmetatable(M, {
__index = function(_, k) return proxies[k] or M[k] end,
__newindex = function(_, k, v)