aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar mitchell <70453897+667e-11@users.noreply.github.com>2011-07-29 18:27:06 -0400
committerGravatar mitchell <70453897+667e-11@users.noreply.github.com>2011-07-29 18:27:06 -0400
commit36675f10b0cefaee7e9451b3eec3dfd715888625 (patch)
tree5a2135ef56b3e52bdf63fb4a82d4cec8c5e41eab
parent32da7ac1a36d2285daa3a0ee280f1730415f04cf (diff)
Eliminated the need for keys.conf and keys.osx.conf.
Thanks to Robert Gieseke for the idea and prototype code.
-rw-r--r--core/.buffer.luadoc1
-rw-r--r--core/gui.lua2
-rw-r--r--doc/manual/9_Preferences.md35
-rw-r--r--modules/lua/api8
-rw-r--r--modules/lua/tags4
-rw-r--r--modules/textadept/adeptsense.lua18
-rw-r--r--modules/textadept/init.lua2
-rw-r--r--modules/textadept/keys.conf165
-rw-r--r--modules/textadept/keys.lua320
-rw-r--r--modules/textadept/keys.osx.conf165
-rw-r--r--modules/textadept/menu.lua408
-rw-r--r--modules/textadept/session.lua28
12 files changed, 508 insertions, 648 deletions
diff --git a/core/.buffer.luadoc b/core/.buffer.luadoc
index 01219b6e..93fe8abe 100644
--- a/core/.buffer.luadoc
+++ b/core/.buffer.luadoc
@@ -2408,6 +2408,7 @@ function buffer.set_lexer(buffer, lang) end
-- Replacement for buffer.get_lexer_language(buffer).
-- @param buffer The focused buffer.
function buffer.get_lexer(buffer) end
+
---
-- Returns the name of the style associated with a style number.
-- @param buffer The focused buffer.
diff --git a/core/gui.lua b/core/gui.lua
index 09540f7e..e0a739b4 100644
--- a/core/gui.lua
+++ b/core/gui.lua
@@ -98,7 +98,7 @@ connect(events.VIEW_NEW, function()
local ctrl_keys = {
'[', ']', '/', '\\', 'Z', 'Y', 'X', 'C', 'V', 'A', 'L', 'T', 'D', 'U'
}
- local ctrl_shift_keys = { 'L', 'T', 'U' }
+ local ctrl_shift_keys = { 'L', 'T', 'U', 'Z' }
for _, key in ipairs(ctrl_keys) do
buffer:clear_cmd_key(string.byte(key), c.SCMOD_CTRL)
end
diff --git a/doc/manual/9_Preferences.md b/doc/manual/9_Preferences.md
index 8e6b0a48..3a19e55b 100644
--- a/doc/manual/9_Preferences.md
+++ b/doc/manual/9_Preferences.md
@@ -75,35 +75,16 @@ the snippet.
##### Key Commands
-The default set of key commands is located in `modules/textadept/keys.conf`
-(`modules/textadept/keys.osx.conf` on Mac OSX) and is loaded by the
-`_m.textadept.menu` module. It is not recommended to edit Textadept's
-`keys.conf` or `keys.osx.conf` for changing the key bindings since your changes
-could be overwritten when updating Textadept. Instead, make a copy in your
-`~/.textadept/` folder and modify that.
-
-Key commands need to be defined manually for keychains or custom functions. You
-can do this in your `~/.textadept/init.lua` or from a file loaded by
-`~/.textadept/init.lua`. For example maybe you want `Ctrl+Shift+A, N` (`⌘⇧A, N`
-on Mac OSX) to create a new buffer instead of `Ctrl+N` (`⌘N`):
-
- keys.cA = {}
- keys.cA.n = new_buffer
+It is not recommended to edit Textadept's `modules/textadept/keys.lua` for
+changing the key bindings since your changes could be overwritten when updating
+Textadept. Instead, modify `keys` from within your `~/.textadept/init.lua` or
+from a file loaded by `~/.textadept/init.lua`. For example maybe you want
+`Ctrl+Shift+N` (`⌘⇧N` on Mac OSX) to create a new buffer instead of `Ctrl+N`
+(`⌘N`):
+
+ keys.cN = new_buffer
keys.cn = nil
-Earlier versions of Textadept manually defined all key commands in
-`modules/textadept/keys.lua` (`keys.cn = new_buffer`, `keys.co = io.open_file`,
-etc.). Now the `menu` module does this automatically by reading the keys in the
-`keys.conf` or `keys.osx.conf` files mentioned earlier. Of course you can still
-use Lua to define commands as demonstrated above. In fact, if you choose to
-exclude loading the menu like in an earlier example above, you will have to
-specify your own set of key commands! (I happen to do this and keep a copy of
-`~/.textadept/modules/textadept/keys.lua` that is loaded by my
-`~/.textadept/init.lua`.) Please note that key commands are _not_ handled by the
-menu; they are still handled as they always have been. Therefore the keys shown
-in the menu could differ from the actual set of key commands if you use Lua to
-redefine them. Menu keys are shown purely for cosmetic, not functional reasons.
-
## Locale
Most messages displayed by Textadept are localized. `core/locale.conf` contains
diff --git a/modules/lua/api b/modules/lua/api
index 4bf67f90..55cb8b22 100644
--- a/modules/lua/api
+++ b/modules/lua/api
@@ -853,6 +853,7 @@ comment_string _m.textadept.editing.comment_string [table]\nComment strings for
compile _m.textadept.run.compile()\nCompiles the file as specified by its extension in the compile_command table.\n@see compile_command\n
compile_command _m.textadept.run.compile_command [table]\nFile extensions and their associated 'compile' actions. Each key is a file\nextension whose value is a either a command line string to execute or a\nfunction returning one. This table is typically populated by language-specific\nmodules.\n
complete _m.textadept.adeptsense.complete(sense, only_fields, only_functions)\nShows an autocompletion list for the symbol behind the caret.\n@param sense The adeptsense returned by adeptsense.new().\n@param only_fields If true, returns list of only fields; defaults to false.\n@param only_functions If true, returns list of only functions; defaults\nto false.\n@return true on success or false.\n@see get_symbol\n@see get_completions\n
+complete_symbol _m.textadept.adeptsense.complete_symbol()\nCompletes the symbol at the current position based on the current lexer's\nAdeptsense. This should be called by key commands and menus instead of\n`complete`.\n
completions _m.textadept.adeptsense.completions [table]\nContains lists of possible completions for known symbols. Each symbol key\nhas a table value that contains a list of field completions with a `fields`\nkey and a list of functions completions with a `functions` key. This table\nis normally populated by load_ctags(), but can also be set by the user.\n
concat table.concat(table [, sep [, i [, j]]])\nGiven an array where all elements are strings or numbers, returns\n`table[i]..sep..table[i+1] ··· sep..table[j]`. The default value for `sep`\nis the empty string, the default for `i` is 1, and the default for `j` is\nthe length of the table. If `i` is greater than `j`, returns the empty string.\n
connect events.connect(event, f, index)\nAdds a handler function to an event.\n@param event The string event name. It is arbitrary and need not be defined\nanywhere.\n@param f The Lua function to add.\n@param index Optional index to insert the handler into.\n@return Index of handler.\n@see disconnect\n
@@ -1092,7 +1093,7 @@ java _G.snippets.java [table]\nContainer for Java-specific snippets.\n
java _m.java [module]\nThe java module. It provides utilities for editing Java code. User tags\nare loaded from _USERHOME/modules/java/tags and user apis are loaded from\n_USERHOME/modules/java/api.\n
join_lines _m.textadept.editing.join_lines()\nJoins the current line with the line below.\n
keys _G.keys [module]\nManages key commands in Textadept.\n
-keys _m.textadept.keys [module]\nDefines additional key commands for Textadept. The primary key commands\nare loaded from _USERHOME/keys.conf, _HOME/modules/textadept/keys.conf,\n_USERHOME/keys.osx.conf, or _HOME/modules/textadept/keys.osx.conf depending\non the platform by _m.textadept.menu. This module, like _m.textadept.menu,\nshould be 'require'ed last.\n
+keys _m.textadept.keys [module]\nDefines key commands for Textadept. This set of key commands is pretty\nstandard among other text editors. This module, should be 'require'ed last,\nbut before _m.textadept.menu.\n
keys_unicode buffer.keys_unicode [bool]\nInterpret keyboard input as Unicode.\n
layout_cache buffer.layout_cache [number]\nThe degree of caching of layout information.\n * `_SCINTILLA.constants.SC_CACHE_NONE` (0): No lines are cached.\n * `_SCINTILLA.constants.SC_CACHE_CARET` (1): The line containing the\n text caret. This is the default.\n * `_SCINTILLA.constants.SC_CACHE_PAGE` (2): Visible lines plus the line\n containing the caret.\n * `_SCINTILLA.constants.SC_CACHE_DOCUMENT` (3): All lines in the\n document.\n\n
ldexp math.ldexp(m, e)\nReturns *m2^e* (`e` should be an integer).\n
@@ -1205,7 +1206,7 @@ math _G.math [module]\nLua math module.\n
max math.max(x, ···)\nReturns the maximum value among its arguments.\n
max_line_state buffer.max_line_state [number]\nThe last line number that has line state. (Read-only)\n
maxn table.maxn(table)\nReturns the largest positive numerical index of the given table, or zero if\nthe table has no positive numerical indices. (To do its job this function\ndoes a linear traversal of the whole table.)\n
-menu _m.textadept.menu [module]\nProvides dynamic menus for Textadept. It also loads key commands\nfrom _USERHOME/keys.conf, _HOME/modules/textadept/keys.conf,\n_USERHOME/keys.osx.conf, or _HOME/modules/textadept/keys.osx.conf depending on\nthe platform. This module, like _m.textadept.keys, should be 'require'ed last.\n
+menu _m.textadept.menu [module]\nProvides dynamic menus for Textadept. This module should be 'require'ed last,\nafter _m.textadept.keys since it looks up defined key commands to show them\nin menus.\n
menubar _m.textadept.menu.menubar [table]\nContains the main menubar.\n
menubar gui.menubar [table]\nA table of GTK menus defining a menubar. (Write-only)\n
mime_types _m.textadept.mime_types [module]\nHandles file-specific settings.\n
@@ -1282,6 +1283,8 @@ print_magnification buffer.print_magnification [number]\nThe print magnification
print_wrap_mode buffer.print_wrap_mode [number]\nPrinting line wrap mode.\n * `_SCINTILLA.constants.SC_WRAP_NONE` (0): Each line of text generates\n one line of output and the line is truncated if it is too long to fit\n into the print area.\n * `_SCINTILLA.constants.SC_WRAP_WORD` (1): Wraps printed output so that\n all characters fit into the print rectangle. Tries to wrap only\n between words as indicated by white space or style changes although\n if a word is longer than a line, it will be wrapped before the line\n end. This is the default.\n * `_SCINTILLA.constants.SC_WRAP_CHAR` (2).\n\n
private_lexer_call buffer.private_lexer_call(buffer, operation, data)\nFor private communication between an application and a known lexer.\n@param buffer The focused buffer.\n@param operation An operation number.\n@param data Number data.\n
process args.process()\nProcesses command line arguments. Add command line switches with\nargs.register(). Any unrecognized arguments are treated as filepaths and\nopened. Generates an 'arg_none' event when no args are present.\n@see register\n
+prompt_load _m.textadept.session.prompt_load()\nPrompts the user for a Textadept session to load.\n
+prompt_save _m.textadept.session.prompt_save()\nPrompts the user to save the current Textadept session to a file.\n
properties _SCINTILLA.properties [table]\nScintilla properties.\n
property buffer.property [table]\nTable of keyword:value string pairs used by a lexer for some optional\nfeatures. (Write-only)\n
property_int buffer.property_int [table]\nInterprets `buffer.property[keyword]` as an integer if found or returns\n0. (Read-only)\n
@@ -1440,6 +1443,7 @@ setupvalue debug.setupvalue(func, up, value)\nThis function assigns the value `v
setvbuf file:setvbuf(mode [, size])\nSets the buffering mode for an output file. There are three available\nmodes: "no": no buffering; the result of any output operation appears\nimmediately. "full": full buffering; output operation is performed only\nwhen the buffer is full (or when you explicitly `flush` the file (see\n`io.flush`)). "line": line buffering; output is buffered until a newline is\noutput or there is any input from some special files (such as a terminal\ndevice). For the last two cases, `size` specifies the size of the buffer,\nin bytes. The default is an appropriate size.\n
shebangs _m.textadept.mime_types.shebangs [table]\nShebang words and their associated lexers.\n
show_apidoc _m.textadept.adeptsense.show_apidoc(sense)\nShows a calltip with API documentation for the symbol behind the caret.\n@param sense The adeptsense returned by adeptsense.new().\n@return true on success or false.\n@see get_symbol\n@see get_apidoc\n
+show_documentation _m.textadept.adeptsense.show_documentation()\nShows API documentation for the symbol at the current position based on the\ncurrent lexer's Adeptsense. This should be called by key commands and menus\ninstead of `show_apidoc`.\n
show_lines buffer.show_lines(buffer, start_line, end_line)\nMake a range of lines visible. This has no effect on fold levels or fold\nflags. start_line can not be hidden.\n@param buffer The focused buffer.\n@param start_line The start line.\n@param end_line The end line.\n
sin math.sin(x)\nReturns the sine of `x` (assumed to be in radians).\n
singular _m.rails.singular\nA map of plural controller names to their singulars. Add key-value pairs to\nthis if singularize() is incorrectly converting your plural controller name\nto its singular model name.\n
diff --git a/modules/lua/tags b/modules/lua/tags
index 1429945b..acce66eb 100644
--- a/modules/lua/tags
+++ b/modules/lua/tags
@@ -878,6 +878,7 @@ comment_string _ 0;" t class:_m.textadept.editing
compile _ 0;" f class:_m.textadept.run
compile_command _ 0;" t class:_m.textadept.run
complete _ 0;" f class:_m.textadept.adeptsense
+complete_symbol _ 0;" f class:_m.textadept.adeptsense
completions _ 0;" t class:_m.textadept.adeptsense
concat _ 0;" f class:table
connect _ 0;" f class:events
@@ -1322,6 +1323,8 @@ print_magnification _ 0;" F class:buffer
print_wrap_mode _ 0;" F class:buffer
private_lexer_call _ 0;" f class:buffer
process _ 0;" f class:args
+prompt_load _ 0;" f class:_m.textadept.session
+prompt_save _ 0;" f class:_m.textadept.session
properties _ 0;" t class:_SCINTILLA
property _ 0;" F class:buffer
property_int _ 0;" F class:buffer
@@ -1480,6 +1483,7 @@ setupvalue _ 0;" f class:debug
setvbuf _ 0;" f class:file
shebangs _ 0;" t class:_m.textadept.mime_types
show_apidoc _ 0;" f class:_m.textadept.adeptsense
+show_documentation _ 0;" f class:_m.textadept.adeptsense
show_lines _ 0;" f class:buffer
sin _ 0;" f class:math
singular _ 0;" F class:_m.rails
diff --git a/modules/textadept/adeptsense.lua b/modules/textadept/adeptsense.lua
index d7c3a9a5..37ee20bc 100644
--- a/modules/textadept/adeptsense.lua
+++ b/modules/textadept/adeptsense.lua
@@ -889,3 +889,21 @@ syntax = {
senses[lang] = sense
return sense
end
+
+---
+-- Completes the symbol at the current position based on the current lexer's
+-- Adeptsense.
+-- This should be called by key commands and menus instead of `complete`.
+function complete_symbol()
+ local m = _m[buffer:get_lexer()]
+ if m and m.sense then m.sense:complete() end
+end
+
+---
+-- Shows API documentation for the symbol at the current position based on the
+-- current lexer's Adeptsense.
+-- This should be called by key commands and menus instead of `show_apidoc`.
+function show_documentation()
+ local m = _m[buffer:get_lexer()]
+ if m and m.sense then m.sense:show_apidoc() end
+end
diff --git a/modules/textadept/init.lua b/modules/textadept/init.lua
index 01493380..12b085c4 100644
--- a/modules/textadept/init.lua
+++ b/modules/textadept/init.lua
@@ -18,5 +18,5 @@ require 'textadept.snapopen'
require 'textadept.snippets'
-- These need to be loaded last.
-require 'textadept.menu'
require 'textadept.keys'
+require 'textadept.menu'
diff --git a/modules/textadept/keys.conf b/modules/textadept/keys.conf
deleted file mode 100644
index 4b7dd023..00000000
--- a/modules/textadept/keys.conf
+++ /dev/null
@@ -1,165 +0,0 @@
-% Windows and Linux menu key commands.
-% This set of key commands is pretty standard among other text editors.
-% Define additional key commands in _USERHOME/modules/textadept/keys.lua.
-
-% Unassigned keys (~ denotes keys reserved by the operating system):
-% c: A B C N p qQ T ~ V X Y ) ] } * \n
-% a: aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpP QrRsStTuUvVwWxXyYzZ_ ) ] } *+-/=~~\n\s
-% ca: aAbBcCdDeE F hH jJkK LmMnN pPqQ t v xXy zZ_"'()[]{}<>* /
-
-% CTRL = 'c' (Control ^)
-% ALT = 'a' (Alt)
-% META = [unused]
-% SHIFT = 's' (Shift ⇧)
-% ADD = ''
-% Control, Alt, Shift, and 'a' = 'caA'
-% Control, Alt, Shift, and '\t' = 'cas\t'
-
-% Multiple keys separated by spaces can be assigned to the same command.
-% Keychains are not supported. Please define chains manually.
-
-% The commands below can either be in English or localized for your locale.
-
-% File
-gtk-new = cn
-gtk-open = co
-Open Recent... = cao
-Reload = cO
-gtk-save = cs
-gtk-save-as = cS
-gtk-close = cw
-Close All = cW
-Load Session... =
-Save Session... =
-gtk-quit = aq
-
-% Edit
-gtk-undo = cz
-gtk-redo = cy cZ
-gtk-cut = cx
-gtk-copy = cc
-gtk-paste = cv
-Duplicate Line = cd
-gtk-delete = del
-gtk-select-all = ca
-Match Brace = cm
-Complete Word = c\n
-Delete Word = adel
-Highlight Word = cH
-Toggle Block Comment = c/
-Transpose Characters = ct
-Join Lines = cJ
-% Select
-Select to Matching Brace = cM
-Select between XML Tags = c<
-Select in XML Tag = c>
-Select in Double Quotes = c"
-Select in Single Quotes = c'
-Select in Parentheses = c(
-Select in Brackets = c[
-Select in Braces = c{
-Select Word = cD
-Select Line = cL
-Select Paragraph = cP
-Select Indented Block = cI
-Select Style = cY
-% Selection
-Upper Case Selection = cau
-Lower Case Selection = caU
-Enclose as XML Tags = a<
-Enclose as Single XML Tag = a>
-Enclose in Single Quotes = a'
-Enclose in Double Quotes = a"
-Enclose in Parentheses = a(
-Enclose in Brackets = a[
-Enclose in Braces = a{
-Grow Selection = c+
-Shrink Selection = c_
-Move Selected Lines Up = csup
-Move Selected Lines Down = csdown
-
-% Search
-gtk-find = cf
-Find Next = cg f3
-Find Previous = cG sf3
-Replace = cr
-Replace All = cR
-Find Incremental = caf
-Find in Files = cF
-Goto Next File Found = cag
-Goto Previous File Found = caG
-gtk-jump-to = cj
-
-% Tools
-Command Entry = ce
-Select Command = cE
-Run = car
-Compile = caR
-Filter Through = c|
-% Adeptsense
-Complete Symbol = c\s
-Show Documentation = ch
-% Snippets
-Insert Snippet... = ck
-Expand Snippet/Next Placeholder = \t
-Previous Snippet Placeholder = s\t
-Cancel Snippet = cK
-% Bookmark
-Toggle Bookmark = cf2
-Clear Bookmarks = csf2
-Next Bookmark = f2
-Previous Bookmark = sf2
-Goto Bookmark... = af2
-% Snapopen
-Snapopen User Home = cu
-Snapopen Textadept Home =
-Snapopen Current Directory = caO
-Show Style = ci
-
-% Buffer
-Next Buffer = c\t cpgdn
-Previous Buffer = cs\t cpgup
-Switch to Buffer... = cb
-% Indentation
-Tab width: 2 =
-Tab width: 3 =
-Tab width: 4 =
-Tab width: 8 =
-Toggle Use Tabs = caT
-Convert Indentation = cai
-% EOL Mode
-CRLF =
-CR =
-LF =
-% Encoding
-UTF-8 Encoding =
-ASCII Encoding =
-ISO-8859-1 Encoding =
-MacRoman Encoding =
-UTF-16 Encoding =
-Select Lexer... = cal
-Refresh Syntax Highlighting = f5
-
-% View
-Next View = ca\t
-Previous View = cas\t
-Split View Vertical = caS
-Split View Horizontal = cas
-Unsplit View = caw
-Unsplit All Views = caW
-Grow View = ca+ ca=
-Shrink View = ca-
-Toggle Current Fold =
-Toggle View EOL = ca\n ca\n\r
-Toggle Wrap Mode = ca\\
-Toggle Show Indent Guides = caI
-Toggle View Whitespace = ca\s
-Toggle Virtual Space = caV
-Zoom In = c=
-Zoom Out = c-
-Reset Zoom = c0
-
-% Help
-Show Manual = f1
-Show LuaDoc = sf1
-gtk-about =
diff --git a/modules/textadept/keys.lua b/modules/textadept/keys.lua
index e39fa796..8aeffbd2 100644
--- a/modules/textadept/keys.lua
+++ b/modules/textadept/keys.lua
@@ -1,41 +1,307 @@
-- Copyright 2007-2011 Mitchell mitchell<att>caladbolg.net. See LICENSE.
local L = locale.localize
+local gui = gui
---
--- Defines additional key commands for Textadept.
--- The primary key commands are loaded from _USERHOME/keys.conf,
--- _HOME/modules/textadept/keys.conf, _USERHOME/keys.osx.conf, or
--- _HOME/modules/textadept/keys.osx.conf depending on the platform by
--- _m.textadept.menu.
--- This module, like _m.textadept.menu, should be 'require'ed last.
+-- Defines key commands for Textadept.
+-- This set of key commands is pretty standard among other text editors.
+-- This module, should be 'require'ed last, but before _m.textadept.menu.
module('_m.textadept.keys', package.seeall)
-local keys = keys
+local keys, _buffer, _view = keys, buffer, view
+local m_textadept, m_editing = _m.textadept, _m.textadept.editing
+local c, OSX = _SCINTILLA.constants, OSX
+-- Utility functions.
+utils = {
+ enclose_as_xml_tags = function()
+ enclose('<', '>')
+ local buffer = buffer
+ 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_in_files = function()
+ gui.find.in_files = true
+ gui.find.focus()
+ end,
+ select_command = function() _m.textadept.menu.select_command() end,
+ snapopen_filedir = function()
+ if buffer.filename then
+ m_textadept.snapopen.open(buffer.filename:match('^(.+)[/\\]'))
+ end
+ end,
+ show_style = function()
+ local buffer = buffer
+ local style = buffer.style_at[buffer.current_pos]
+ local text = string.format("%s %s\n%s %s (%d)", L('Lexer'),
+ buffer:get_lexer(), L('Style'),
+ buffer:get_style_name(style), style)
+ buffer:call_tip_show(buffer.current_pos, text)
+ end,
+ set_indentation = function(i)
+ buffer.indent, buffer.tab_width = i, 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] = buffer[property] == 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_eo_ls(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 + 10 end end,
+ shrink = function() if view.size then view.size = view.size - 10 end end,
+ toggle_current_fold = function()
+ local buffer = buffer
+ buffer:toggle_fold(buffer:line_from_position(buffer.current_pos))
+ end,
+ reset_zoom = function() buffer.zoom = 0 end,
+ open_webpage = function(url)
+ local cmd
+ if WIN32 then
+ cmd = string.format('start "" "%s"', url)
+ local p = io.popen(cmd)
+ if not p then error(L('Error loading webpage:')..url) end
+ else
+ cmd = string.format(OSX and 'open "file://%s"' or 'xdg-open "%s" &', url)
+ if os.execute(cmd) ~= 0 then error(L('Error loading webpage:')..url) end
+ end
+ end
+}
+-- 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'
+}
+local function constantize_menu_buffer_functions()
+ local buffer = buffer
+ for _, f in ipairs(menu_buffer_functions) do buffer[f] = buffer[f] end
+end
+events.connect(events.BUFFER_NEW, constantize_menu_buffer_functions)
+if not RESETTING then constantize_menu_buffer_functions() end
+
+--[[
+ Windows and Linux menu key commands.
+
+ Unassigned keys (~ denotes keys reserved by the operating system):
+ c: A B C H N p qQ T ~ V X Y ) ] } * \n
+ a: aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpP QrRsStTuUvVwWxXyYzZ_ ) ] } *+-/=~~\n\s
+ ca: aAbBcCdDeE F h jJkK LmMnN pPqQ t v xXy zZ_"'()[]{}<>* /
+
+ CTRL = 'c' (Control ^)
+ ALT = 'a' (Alt)
+ META = [unused]
+ SHIFT = 's' (Shift ⇧)
+ ADD = ''
+ Control, Alt, Shift, and 'a' = 'caA'
+ Control, Alt, Shift, and '\t' = 'cas\t'
+
+ Mac OSX menu key commands.
+
+ Unassigned keys (~ denotes keys reserved by the operating system):
+ c: A B C ~ JkK ~M N p ~ tT U V Xy ) ] } * ~~\n~~
+ ca: aAbBcC~DeE F ~HiIjJkK L~MnN pPq~rRsStTuUvVwWxXyYzZ_"'()[]{}<>*+-/= \n~~
+ m: cC D gG H J K L oO qQ v xXyYzZ_ ) ] } * /
+
+ CTRL = 'c' (Command ⌘)
+ ALT = 'a' (Alt/option ⌥)
+ META = 'm' (Control ^)
+ SHIFT = 's' (Shift ⇧)
+ ADD = ''
+ Command, Alt, Shift, and 'a' = 'caA'
+ Command, Alt, Shift, and '\t' = 'cas\t'
+]]--
+
+-- File.
+keys.cn = new_buffer
+keys.co = io.open_file
+keys.cao = io.open_recent_file
+keys.cO = _buffer.reload
+keys.cs = _buffer.save
+keys.cS = _buffer.save_as
+keys.cw = _buffer.close
+keys.cW = io.close_all
+-- TODO: m_textadept.sessions.prompt_load
+-- TODO: m_textadept.sessions.prompt_save
+keys[not OSX and 'aq' or 'cq'] = quit
+
+-- Edit.
+keys.cz = _buffer.undo
+if not OSX then keys.cy = _buffer.redo end
+keys.cZ = _buffer.redo
+keys.cx = _buffer.cut
+keys.cc = _buffer.copy
+keys.cv = _buffer.paste
+keys.cd = _buffer.line_duplicate
+keys.del = _buffer.clear
+keys.ca = _buffer.select_all
+keys[not OSX and 'cm' or 'mm'] = m_editing.match_brace
+keys[not OSX and 'c\n' or 'mesc'] = { m_editing.autocomplete_word, '%w_' }
+keys[not OSX and 'adel' or 'mdel'] = { m_editing.current_word, 'delete' }
+keys[not OSX and 'caH' or 'cH'] = m_editing.highlight_word
+keys['c/'] = m_editing.block_comment
+keys[not OSX and 'ct' or 'mt'] = m_editing.transpose_chars
+keys[not OSX and 'cJ' or 'mj'] = m_editing.join_lines
+-- Select.
+keys[not OSX and 'cM' or 'mM'] = { m_editing.match_brace, 'select' }
+keys['c<'] = { m_editing.select_enclosed, '>', '<' }
+keys['c>'] = { m_editing.select_enclosed, '<', '>' }
+keys["c'"] = { m_editing.select_enclosed, "'", "'" }
+keys['c"'] = { m_editing.select_enclosed, '"', '"' }
+keys['c('] = { m_editing.select_enclosed, '(', ')' }
+keys['c['] = { m_editing.select_enclosed, '[', ']' }
+keys['c{'] = { m_editing.select_enclosed, '{', '}' }
+keys.cD = { m_editing.current_word, 'select' }
+keys.cL = m_editing.select_line
+keys.cP = m_editing.select_paragraph
+keys.cI = m_editing.select_indented_block
+keys.cY = m_editing.select_style
+-- Selection.
+keys[not OSX and 'cau' or 'mu'] = _buffer.upper_case
+keys[not OSX and 'caU' or 'mU'] = _buffer.lower_case
+keys[not OSX and 'a<' or 'm<'] = utils.enclose_as_xml_tags
+keys[not OSX and 'a>' or 'm>'] = { m_editing.enclose, '<', ' />' }
+keys[not OSX and "a'" or "m'"] = { m_editing.enclose, "'", "'" }
+keys[not OSX and 'a"' or 'm"'] = { m_editing.enclose, '"', '"' }
+keys[not OSX and 'a(' or 'm('] = { m_editing.enclose, '(', ')' }
+keys[not OSX and 'a[' or 'm['] = { m_editing.enclose, '[', ']' }
+keys[not OSX and 'a{' or 'm{'] = { m_editing.enclose, '{', '}' }
+keys['c+'] = { m_editing.grow_selection, 1 }
+keys['c_'] = { m_editing.grow_selection, -1 }
+keys[not OSX and 'csup' or 'msup'] = _buffer.move_selected_lines_up
+keys[not OSX and 'csdown' or 'msdown'] = _buffer.move_selected_lines_down
+
+-- Search.
+keys.cf = gui.find.focus
+keys.cg = gui.find.find_next
+if not OSX then keys.f3 = gui.find.find_next end
+keys.cG = gui.find.find_prev
+if not OSX then keys.sf3 = gui.find.find_prev end
+keys.cr = gui.find.replace
+keys.cR = gui.find.replace_all
+keys.caf = gui.find.find_incremental
+keys.cF = utils.find_in_files
+keys.cag = { gui.find.goto_file_in_list, true }
+keys.caG = { gui.find.goto_file_in_list, false }
+keys.cj = m_editing.goto_line
+
+-- Tools.
+keys.ce = gui.command_entry.focus
+keys.cE = utils.select_command
+keys[not OSX and 'car' or 'mr'] = m_textadept.run.run
+keys[not OSX and 'caR' or 'mR'] = m_textadept.run.compile
+keys['c|'] = m_textadept.filter_through.filter_through
+-- Adeptsense.
+keys[not OSX and 'c ' or 'aesc'] = m_textadept.adeptsense.complete_symbol
+keys[not OSX and 'ch' or 'mh'] = m_textadept.adeptsense.show_documentation
+-- Snippets.
+keys[not OSX and 'ck' or 'a\t'] = m_textadept.snippets._select
+keys['\t'] = m_textadept.snippets._insert
+keys['s\t'] = m_textadept.snippets._previous
+keys[not OSX and 'cK' or 'as\t'] = m_textadept.snippets._cancel_current
+-- Bookmark.
+keys.cf2 = m_textadept.bookmarks.toggle
+keys.csf2 = m_textadept.bookmarks.clear
+keys.f2 = m_textadept.bookmarks.goto_next
+keys.sf2 = m_textadept.bookmarks.goto_prev
+keys.af2 = m_textadept.bookmarks.goto
+-- Snapopen.
+keys.cu = { m_textadept.snapopen.open, _USERHOME }
+-- TODO: { m_textadept.snapopen.open, _HOME }
+keys.caO = utils.snapopen_filedir
+keys.ci = utils.show_style
+
+-- Buffer.
+keys[not OSX and 'c\t' or 'm`'] = { _view.goto_buffer, _view, 1, false }
+if not OSX then keys.cpgdn = keys['c\t'] end
+keys[not OSX and 'cs\t' or 'm~'] = { _view.goto_buffer, _view, -1, false }
+if not OSX then keys.cpgup = keys['cs\t'] end
+keys.cb = gui.switch_buffer
+-- 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 'caT' or 'mT'] = { utils.toggle_property, 'use_tabs' }
+keys[not OSX and 'cai' or 'mi'] = m_editing.convert_indentation
+-- EOL Mode.
+-- TODO: { utils.set_eol_mode, c.SC_EOL_CRLF }
+-- TODO: { utils.set_eol_mode, c.SC_EOL_CR }
+-- TODO: { utils.set_eol_mode, c.SC_EOL_LF }
+-- 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.cal = m_textadept.mime_types.select_lexer
+keys.f5 = { _buffer.colourise, _buffer, 0, -1 }
+
+-- View.
+keys[not OSX and 'ca\t' or 'm\t'] = { gui.goto_view, 1, false }
+keys[not OSX and 'cas\t' or 'ms\t'] = { gui.goto_view, -1, false }
+keys[not OSX and 'caS' or 'mS'] = { _view.split, _view }
+keys[not OSX and 'cas' or 'ms'] = { _view.split, _view, false }
+keys[not OSX and 'caw' or 'mw'] = { _view.unsplit, _view }
+keys[not OSX and 'caW' or 'mW'] = utils.unsplit_all
+keys[not OSX and 'ca+' or 'm+'] = { utils.grow, 10 }
+keys[not OSX and 'ca=' or 'm='] = { utils.grow, 10 }
+keys[not OSX and 'ca-' or 'm-'] = { utils.shrink, 10 }
+-- TODO: utils.toggle_current_fold
+keys[not OSX and 'ca\n' or 'm\n'] = { utils.toggle_property, 'view_eol' }
+if not OSX then keys['ca\n\r'] = keys['ca\n'] end
+keys[not OSX and 'ca\\' or 'm\\'] = { utils.toggle_property, 'wrap_mode' }
+keys[not OSX and 'caI' or 'mI'] = { utils.toggle_property, 'indentation_guides' }
+keys[not OSX and 'ca ' or 'm '] = { utils.toggle_property, 'view_ws' }
+keys[not OSX and 'caV' or 'mV'] = { utils.toggle_property, 'virtual_space_options', c.SCVS_USERACCESSIBLE }
+keys['c='] = _buffer.zoom_in
+keys['c-'] = _buffer.zoom_out
+keys.c0 = utils.reset_zoom
+
+-- Help.
+keys.f1 = { utils.open_webpage, _HOME..'/doc/manual/1_Introduction.html' }
+keys.sf1 = { utils.open_webpage, _HOME..'/doc/index.html' }
+-- TODO: { gui.dialog, 'ok-msgbox', '--title', 'Textadept'
+-- '--informative-text', _RELEASE, '--no-cancel' }
+
+-- Movement commands.
if OSX then
- -- See keys.osx.conf for unassigned keys.
keys.mk = function()
buffer:line_end_extend()
buffer:cut()
end
- local buffer = buffer
- keys.mf = buffer.char_right
- keys.mF = buffer.char_right_extend
- keys.amf = buffer.word_right
- keys.amF = buffer.word_right_extend
- keys.mb = buffer.char_left
- keys.mB = buffer.char_left_extend
- keys.amb = buffer.word_left
- keys.amB = buffer.word_left_extend
- keys.mn = buffer.line_down
- keys.mN = buffer.line_down_extend
- keys.mp = buffer.line_up
- keys.mP = buffer.line_up_extend
- keys.ma = buffer.vc_home
- keys.mA = buffer.vc_home_extend
- keys.me = buffer.line_end
- keys.mE = buffer.line_end_extend
- keys.md = buffer.clear
- keys.ml = buffer.vertical_centre_caret
+ keys.mf = _buffer.char_right
+ keys.mF = _buffer.char_right_extend
+ keys.amf = _buffer.word_right
+ keys.amF = _buffer.word_right_extend
+ keys.mb = _buffer.char_left
+ keys.mB = _buffer.char_left_extend
+ keys.amb = _buffer.word_left
+ keys.amB = _buffer.word_left_extend
+ keys.mn = _buffer.line_down
+ keys.mN = _buffer.line_down_extend
+ keys.mp = _buffer.line_up
+ keys.mP = _buffer.line_up_extend
+ keys.ma = _buffer.vc_home
+ keys.mA = _buffer.vc_home_extend
+ keys.me = _buffer.line_end
+ keys.mE = _buffer.line_end_extend
+ keys.md = _buffer.clear
+ keys.ml = _buffer.vertical_centre_caret
end
diff --git a/modules/textadept/keys.osx.conf b/modules/textadept/keys.osx.conf
deleted file mode 100644
index 42492597..00000000
--- a/modules/textadept/keys.osx.conf
+++ /dev/null
@@ -1,165 +0,0 @@
-% Mac OSX menu key commands.
-% This set of key commands is pretty standard among other text editors.
-% Define additional key commands in _USERHOME/modules/textadept/keys.lua.
-
-% Unassigned keys (~ denotes keys reserved by the operating system):
-% c: A B C ~ JkK ~M N p ~ tT U V Xy ) ] } * ~~\n~~
-% ca: aAbBcC~DeE F ~HiIjJkK L~MnN pPq~rRsStTuUvVwWxXyYzZ_"'()[]{}<>*+-/= \n~~
-% m: cC D gG H J K L oO qQ v xXyYzZ_ ) ] } * /
-
-% CTRL = 'c' (Command ⌘)
-% ALT = 'a' (Alt/option ⌥)
-% META = 'm' (Control ^)
-% SHIFT = 's' (Shift ⇧)
-% ADD = ''
-% Command, Alt, Shift, and 'a' = 'caA'
-% Command, Alt, Shift, and '\t' = 'cas\t'
-
-% Multiple keys separated by spaces can be assigned to the same command.
-% Keychains are not supported. Please define chains manually.
-
-% The commands below can either be in English or localized for your locale.
-
-% File
-gtk-new = cn
-gtk-open = co
-Open Recent... = cao
-Reload = cO
-gtk-save = cs
-gtk-save-as = cS
-gtk-close = cw
-Close All = cW
-Load Session... =
-Save Session... =
-gtk-quit = cq
-
-% Edit
-gtk-undo = cz
-gtk-redo = cZ
-gtk-cut = cx
-gtk-copy = cc
-gtk-paste = cv
-Duplicate Line = cd
-gtk-delete = del
-gtk-select-all = ca
-Match Brace = mm
-Complete Word = mesc
-Delete Word = mdel
-Highlight Word = cH
-Toggle Block Comment = c/
-Transpose Characters = mt
-Join Lines = mj
-% Select
-Select to Matching Brace = mM
-Select between XML Tags = c<
-Select in XML Tag = c>
-Select in Double Quotes = c"
-Select in Single Quotes = c'
-Select in Parentheses = c(
-Select in Brackets = c[
-Select in Braces = c{
-Select Word = cD
-Select Line = cL
-Select Paragraph = cP
-Select Indented Block = cI
-Select Style = cY
-% Selection
-Upper Case Selection = mu
-Lower Case Selection = mU
-Enclose as XML Tags = m<
-Enclose as Single XML Tag = m>
-Enclose in Single Quotes = m'
-Enclose in Double Quotes = m"
-Enclose in Parentheses = m(
-Enclose in Brackets = m[
-Enclose in Braces = m{
-Grow Selection = c+
-Shrink Selection = c_
-Move Selected Lines Up = msdown
-Move Selected Lines Down = msup
-
-% Search
-gtk-find = cf
-Find Next = cg
-Find Previous = cG
-Replace = cr
-Replace All = cR
-Find Incremental = caf
-Find in Files = cF
-Goto Next File Found = cag
-Goto Previous File Found = caG
-gtk-jump-to = cj
-
-% Tools
-Command Entry = ce
-Select Command = cE
-Run = mr
-Compile = mR
-Filter Through = c|
-% Adeptsense
-Complete Symbol = aesc
-Show Documentation = mh
-% Snippets
-Insert Snippet... = a\t
-Expand Snippet/Next Placeholder = \t
-Previous Snippet Placeholder = s\t
-Cancel Snippet = as\t
-% Bookmark
-Toggle Bookmark = cf2
-Clear Bookmarks = csf2
-Next Bookmark = f2
-Previous Bookmark = sf2
-Goto Bookmark... = af2
-% Snapopen
-Snapopen User Home = cu
-Snapopen Textadept Home =
-Snapopen Current Directory = caO
-Show Style = ci
-
-% Buffer
-Next Buffer = m`
-Previous Buffer = m~
-Switch to Buffer... = cb
-% Indentation
-Tab width: 2 =
-Tab width: 3 =
-Tab width: 4 =
-Tab width: 8 =
-Toggle Use Tabs = mT
-Convert Indentation = mi
-% EOL Mode
-CRLF =
-CR =
-LF =
-% Encoding
-UTF-8 Encoding =
-ASCII Encoding =
-ISO-8859-1 Encoding =
-MacRoman Encoding =
-UTF-16 Encoding =
-Select Lexer... = cal
-Refresh Syntax Highlighting = f5
-
-% View
-Next View = m\t
-Previous View = ms\t
-Split View Vertical = mS
-Split View Horizontal = ms
-Unsplit View = mw
-Unsplit All Views = mW
-Grow View = m+ m=
-Shrink View = m-
-Toggle Current Fold =
-Toggle View EOL = m\n
-Toggle Wrap Mode = m\\
-Toggle Show Indent Guides = mI
-Toggle View Whitespace = m\s
-Toggle Virtual Space = mV
-Zoom In = c=
-Zoom Out = c-
-Reset Zoom = c0
-
-% Help
-Show Manual = f1
-Show LuaDoc = sf1
-gtk-about =
diff --git a/modules/textadept/menu.lua b/modules/textadept/menu.lua
index d9841946..efe18e1f 100644
--- a/modules/textadept/menu.lua
+++ b/modules/textadept/menu.lua
@@ -2,83 +2,30 @@
-- Contributions from Robert Gieseke.
local L = locale.localize
-local events = events
local gui = gui
---
-- Provides dynamic menus for Textadept.
--- It also loads key commands from _USERHOME/keys.conf,
--- _HOME/modules/textadept/keys.conf, _USERHOME/keys.osx.conf, or
--- _HOME/modules/textadept/keys.osx.conf depending on the platform.
--- This module, like _m.textadept.keys, should be 'require'ed last.
+-- This module should be 'require'ed last, after _m.textadept.keys since it
+-- looks up defined key commands to show them in menus.
module('_m.textadept.menu', package.seeall)
local _buffer, _view = buffer, view
local m_textadept, m_editing = _m.textadept, _m.textadept.editing
-local SEPARATOR = { 'separator' }
+local c, SEPARATOR = _SCINTILLA.constants, { 'separator' }
+local utils = _m.textadept.keys.utils
--- Load menu key commands.
-local K = {}
-local escapes = {
- ['\\b'] = '\b', ['\\n'] = '\n', ['\\r'] = '\r', ['\\t'] = '\t',
- ['\\\\'] = '\\', ['\\s'] = ' '
-}
-local conf = 'keys'..(OSX and '.osx' or '')..'.conf'
-local f = io.open(_USERHOME..'/'..conf)
-if not f then f = io.open(_HOME..'/modules/textadept/'..conf) end
-for line in f:lines() do
- if not line:find('^%s*%%') then
- local id, keys = line:match('^(.-)%s*=%s*(.+)$')
- if id and keys then
- K[id] = {}
- for key in keys:gmatch('%S+') do
- K[id][#K[id] + 1] = key:gsub('\\[bnrt\\s]', escapes)
- end
- end
+-- Get a string uniquely identifying a key command.
+-- This is used to match menu items with key commands to show the key shortcut.
+-- @param f A value in the `keys` table.
+local function get_id(f)
+ local id = ''
+ if type(f) == 'function' then
+ id = tostring(f)
+ elseif type(f) == 'table' then
+ for _, v in ipairs(f) do id = id..tostring(v) end
end
-end
-f:close()
-
-local function set_encoding(encoding)
- buffer:set_encoding(encoding)
- events.emit(events.UPDATE_UI) -- for updating statusbar
-end
-local function toggle_setting(setting, i)
- local state = buffer[setting]
- if type(state) == 'boolean' then
- buffer[setting] = not state
- elseif type(state) == 'number' then
- buffer[setting] = buffer[setting] == 0 and (i or 1) or 0
- end
- events.emit(events.UPDATE_UI) -- for updating statusbar
-end
-local function set_indentation(i)
- buffer.indent, buffer.tab_width = i, i
- events.emit(events.UPDATE_UI) -- for updating statusbar
-end
-local function set_eol_mode(mode)
- buffer.eol_mode = mode
- buffer:convert_eo_ls(mode)
- events.emit(events.UPDATE_UI) -- for updating statusbar
-end
-local function open_webpage(url)
- local cmd
- if WIN32 then
- cmd = string.format('start "" "%s"', url)
- local p = io.popen(cmd)
- if not p then error(L('Error loading webpage:')..url) end
- else
- cmd = string.format(OSX and 'open "file://%s"' or 'xdg-open "%s" &', url)
- if os.execute(cmd) ~= 0 then error(L('Error loading webpage:')..url) end
- end
-end
-
--- Creates a menuitem readable by read_menu_table().
--- @param label The label that will be localized.
--- @param f The function or table.
-local function menuitem(label, f)
- return { L(label), f,
- K[L(label):gsub('_([^_])', '%1')] or K[label:gsub('_([^_])', '%1')] }
+ return id
end
---
@@ -87,242 +34,183 @@ end
-- @name menubar
menubar = {
{ title = L('File'),
- menuitem('gtk-new', new_buffer),
- menuitem('gtk-open', io.open_file),
- menuitem('Open Recent...', io.open_recent_file),
- menuitem('Reload', _buffer.reload),
- menuitem('gtk-save', _buffer.save),
- menuitem('gtk-save-as', _buffer.save_as),
+ { L('gtk-new'), new_buffer },
+ { L('gtk-open'), io.open_file },
+ { L('Open Recent...'), io.open_recent_file },
+ { L('Reload'), _buffer.reload },
+ { L('gtk-save'), _buffer.save },
+ { L('gtk-save-as'), _buffer.save_as },
SEPARATOR,
- menuitem('gtk-close', _buffer.close),
- menuitem('Close All', io.close_all),
+ { L('gtk-close'), _buffer.close },
+ { L('Close All'), io.close_all },
SEPARATOR,
- menuitem('Load Session...', function()
- local session_file = _SESSIONFILE or ''
- local utf8_filename = gui.dialog('fileselect',
- '--title', L('Load Session'),
- '--with-directory',
- session_file:match('.+[/\\]') or '',
- '--with-file',
- session_file:match('[^/\\]+$') or '',
- '--no-newline')
- if #utf8_filename > 0 then
- _m.textadept.session.load(utf8_filename:iconv(_CHARSET, 'UTF-8'))
- end
- end),
- menuitem('Save Session...', function()
- local session_file = _SESSIONFILE or ''
- local utf8_filename = gui.dialog('filesave',
- '--title', L('Save Session'),
- '--with-directory',
- session_file:match('.+[/\\]') or '',
- '--with-file',
- session_file:match('[^/\\]+$') or '',
- '--no-newline')
- if #utf8_filename > 0 then
- _m.textadept.session.save(utf8_filename:iconv(_CHARSET, 'UTF-8'))
- end
- end),
+ { L('Load Session...'), m_textadept.session.prompt_load },
+ { L('Save Session...'), m_textadept.session.prompt_save },
SEPARATOR,
- menuitem('gtk-quit', quit),
+ { L('gtk-quit'), quit },
},
{ title = L('Edit'),
- menuitem('gtk-undo', _buffer.undo),
- menuitem('gtk-redo', _buffer.redo),
+ { L('gtk-undo'), _buffer.undo },
+ { L('gtk-redo'), _buffer.redo },
SEPARATOR,
- menuitem('gtk-cut', _buffer.cut),
- menuitem('gtk-copy', _buffer.copy),
- menuitem('gtk-paste', _buffer.paste),
- menuitem('Duplicate Line', _buffer.line_duplicate),
- menuitem('gtk-delete', _buffer.clear),
- menuitem('gtk-select-all', _buffer.select_all),
+ { L('gtk-cut'), _buffer.cut },
+ { L('gtk-copy'), _buffer.copy },
+ { L('gtk-paste'), _buffer.paste },
+ { L('Duplicate Line'), _buffer.line_duplicate },
+ { L('gtk-delete'), _buffer.clear },
+ { L('gtk-select-all'), _buffer.select_all },
SEPARATOR,
- menuitem('Match Brace', m_editing.match_brace),
- menuitem('Complete Word', { m_editing.autocomplete_word, '%w_' }),
- menuitem('Delete Word', { m_editing.current_word, 'delete' }),
- menuitem('Highlight Word', m_editing.highlight_word),
- menuitem('Toggle Block Comment', m_editing.block_comment),
- menuitem('Transpose Characters', m_editing.transpose_chars),
- menuitem('Join Lines', m_editing.join_lines),
+ { L('Match Brace'), m_editing.match_brace },
+ { L('Complete Word'), { m_editing.autocomplete_word, '%w_' } },
+ { L('Delete Word'), { m_editing.current_word, 'delete' } },
+ { L('Highlight Word'), m_editing.highlight_word },
+ { L('Toggle Block Comment'), m_editing.block_comment },
+ { L('Transpose Characters'), m_editing.transpose_chars },
+ { L('Join Lines'), m_editing.join_lines },
{ title = L('Select'),
- menuitem('Select to Matching Brace', { m_editing.match_brace, 'select' }),
- menuitem('Select between XML Tags',
- { m_editing.select_enclosed, '>', '<' }),
- menuitem('Select in XML Tag', { m_editing.select_enclosed, '<', '>' }),
- menuitem('Select in Double Quotes',
- { m_editing.select_enclosed, '"', '"' }),
- menuitem('Select in Single Quotes',
- { m_editing.select_enclosed, "'", "'" }),
- menuitem('Select in Parentheses',
- { m_editing.select_enclosed, '(', ')' }),
- menuitem('Select in Brackets', { m_editing.select_enclosed, '[', ']' }),
- menuitem('Select in Braces', { m_editing.select_enclosed, '{', '}' }),
- menuitem('Select Word', { m_editing.current_word, 'select' }),
- menuitem('Select Line', m_editing.select_line),
- menuitem('Select Paragraph', m_editing.select_paragraph),
- menuitem('Select Indented Block', m_editing.select_indented_block),
- menuitem('Select Style', m_editing.select_style),
+ { L('Select to Matching Brace'), { m_editing.match_brace, 'select' } },
+ { L('Select between XML Tags'), { m_editing.select_enclosed, '>', '<' } },
+ { L('Select in XML Tag'), { m_editing.select_enclosed, '<', '>' } },
+ { L('Select in Single Quotes'), { m_editing.select_enclosed, "'", "'" } },
+ { L('Select in Double Quotes'), { m_editing.select_enclosed, '"', '"' } },
+ { L('Select in Parentheses'), { m_editing.select_enclosed, '(', ')' } },
+ { L('Select in Brackets'), { m_editing.select_enclosed, '[', ']' } },
+ { L('Select in Braces'), { m_editing.select_enclosed, '{', '}' } },
+ { L('Select Word'), { m_editing.current_word, 'select' } },
+ { L('Select Line'), m_editing.select_line },
+ { L('Select Paragraph'), m_editing.select_paragraph },
+ { L('Select Indented Block'), m_editing.select_indented_block },
+ { L('Select Style'), m_editing.select_style },
},
{ title = L('Selection'),
- menuitem('Upper Case Selection', _buffer.upper_case),
- menuitem('Lower Case Selection', _buffer.lower_case),
+ { L('Upper Case Selection'), _buffer.upper_case },
+ { L('Lower Case Selection'), _buffer.lower_case },
SEPARATOR,
- menuitem('Enclose as XML Tags', function()
- m_editing.enclose('<', '>')
- local buffer = buffer
- 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),
- menuitem('Enclose as Single XML Tag', { m_editing.enclose, '<', ' />' }),
- menuitem('Enclose in Single Quotes', { m_editing.enclose, "'", "'" }),
- menuitem('Enclose in Double Quotes', { m_editing.enclose, '"', '"' }),
- menuitem('Enclose in Parentheses', { m_editing.enclose, '(', ')' }),
- menuitem('Enclose in Brackets', { m_editing.enclose, '[', ']' }),
- menuitem('Enclose in Braces', { m_editing.enclose, '{', '}' }),
+ { L('Enclose as XML Tags'), utils.enclose_as_xml_tags },
+ { L('Enclose as Single XML Tag'), { m_editing.enclose, '<', ' />' } },
+ { L('Enclose in Single Quotes'), { m_editing.enclose, "'", "'" } },
+ { L('Enclose in Double Quotes'), { m_editing.enclose, '"', '"' } },
+ { L('Enclose in Parentheses'), { m_editing.enclose, '(', ')' } },
+ { L('Enclose in Brackets'), { m_editing.enclose, '[', ']' } },
+ { L('Enclose in Braces'), { m_editing.enclose, '{', '}' } },
SEPARATOR,
- menuitem('Grow Selection', { m_editing.grow_selection, 1 }),
- menuitem('Shrink Selection', { m_editing.grow_selection, -1 }),
+ { L('Grow Selection'), { m_editing.grow_selection, 1 } },
+ { L('Shrink Selection'), { m_editing.grow_selection, -1 } },
SEPARATOR,
- menuitem('Move Selected Lines Up', _buffer.move_selected_lines_up),
- menuitem('Move Selected Lines Down', _buffer.move_selected_lines_down),
+ { L('Move Selected Lines Up'), _buffer.move_selected_lines_up },
+ { L('Move Selected Lines Down'), _buffer.move_selected_lines_down },
},
},
{ title = L('Search'),
- menuitem('gtk-find', gui.find.focus),
- menuitem('Find Next', gui.find.find_next),
- menuitem('Find Previous', gui.find.find_prev),
- menuitem('Replace', gui.find.replace),
- menuitem('Replace All', gui.find.replace_all),
- menuitem('Find Incremental', gui.find.find_incremental),
+ { L('gtk-find'), gui.find.focus },
+ { L('Find Next'), gui.find.find_next },
+ { L('Find Previous'), gui.find.find_prev },
+ { L('Replace'), gui.find.replace },
+ { L('Replace All'), gui.find.replace_all },
+ { L('Find Incremental'), gui.find.find_incremental },
SEPARATOR,
- menuitem('Find in Files', function()
- gui.find.in_files = true
- gui.find.focus()
- end),
- menuitem('Goto Next File Found', { gui.find.goto_file_in_list, true }),
- menuitem('Goto Previous File Found', { gui.find.goto_file_in_list, false }),
+ { L('Find in Files'), utils.find_in_files },
+ { L('Goto Next File Found'), { gui.find.goto_file_in_list, true } },
+ { L('Goto Previous File Found'), { gui.find.goto_file_in_list, false } },
SEPARATOR,
- menuitem('gtk-jump-to', m_editing.goto_line),
+ { L('gtk-jump-to'), m_editing.goto_line },
},
{ title = L('Tools'),
- menuitem('Command Entry', gui.command_entry.focus),
- menuitem('Select Command', function() _M.select_command() end),
+ { L('Command Entry'), gui.command_entry.focus },
+ { L('Select Command'), utils.select_command },
SEPARATOR,
- menuitem('Run', m_textadept.run.run),
- menuitem('Compile', m_textadept.run.compile),
- menuitem('Filter Through', _m.textadept.filter_through.filter_through),
+ { L('Run'), m_textadept.run.run },
+ { L('Compile'), m_textadept.run.compile },
+ { L('Filter Through'), _m.textadept.filter_through.filter_through },
SEPARATOR,
{ title = L('Adeptsense'),
- menuitem('Complete Symbol', function()
- local m = _m[buffer:get_lexer()]
- if m and m.sense then m.sense:complete() end
- end),
- menuitem('Show Documentation', function()
- local m = _m[buffer:get_lexer()]
- if m and m.sense then m.sense:show_apidoc() end
- end),
+ { L('Complete Symbol'), m_textadept.adeptsense.complete_symbol },
+ { L('Show Documentation'), m_textadept.adeptsense.show_documentation },
},
{ title = L('Snippets'),
- menuitem('Insert Snippet...', m_textadept.snippets._select),
- menuitem('Expand Snippet/Next Placeholder', m_textadept.snippets._insert),
- menuitem('Previous Snippet Placeholder', m_textadept.snippets._previous),
- menuitem('Cancel Snippet', m_textadept.snippets._cancel_current),
+ { L('Insert Snippet...'), m_textadept.snippets._select },
+ { L('Expand Snippet/Next Placeholder'), m_textadept.snippets._insert },
+ { L('Previous Snippet Placeholder'), m_textadept.snippets._previous },
+ { L('Cancel Snippet'), m_textadept.snippets._cancel_current },
},
{ title = L('Bookmark'),
- menuitem('Toggle Bookmark', m_textadept.bookmarks.toggle),
- menuitem('Clear Bookmarks', m_textadept.bookmarks.clear),
- menuitem('Next Bookmark', m_textadept.bookmarks.goto_next),
- menuitem('Previous Bookmark', m_textadept.bookmarks.goto_prev),
- menuitem('Goto Bookmark...', m_textadept.bookmarks.goto),
+ { L('Toggle Bookmark'), m_textadept.bookmarks.toggle },
+ { L('Clear Bookmarks'), m_textadept.bookmarks.clear },
+ { L('Next Bookmark'), m_textadept.bookmarks.goto_next },
+ { L('Previous Bookmark'), m_textadept.bookmarks.goto_prev },
+ { L('Goto Bookmark...'), m_textadept.bookmarks.goto },
},
{ title = L('Snapopen'),
- menuitem('Snapopen User Home', { m_textadept.snapopen.open, _USERHOME }),
- menuitem('Snapopen Textadept Home', { m_textadept.snapopen.open, _HOME }),
- menuitem('Snapopen Current Directory', function()
- if buffer.filename then
- m_textadept.snapopen.open(buffer.filename:match('^(.+)[/\]'))
- end
- end),
+ { L('Snapopen User Home'), { m_textadept.snapopen.open, _USERHOME } },
+ { L('Snapopen Textadept Home'), { m_textadept.snapopen.open, _HOME } },
+ { L('Snapopen Current Directory'), utils.snapopen_filedir },
},
SEPARATOR,
- menuitem('Show Style', function()
- local buffer = buffer
- local style = buffer.style_at[buffer.current_pos]
- local text = string.format("%s %s\n%s %s (%d)", L('Lexer'),
- buffer:get_lexer(), L('Style'),
- buffer:get_style_name(style), style)
- buffer:call_tip_show(buffer.current_pos, text)
- end),
+ { L('Show Style'), utils.show_style },
},
{ title = L('Buffer'),
- menuitem('Next Buffer', { _view.goto_buffer, _view, 1, false }),
- menuitem('Previous Buffer', { _view.goto_buffer, _view, -1, false }),
- menuitem('Switch to Buffer...', gui.switch_buffer),
+ { L('Next Buffer'), { _view.goto_buffer, _view, 1, false } },
+ { L('Previous Buffer'), { _view.goto_buffer, _view, -1, false } },
+ { L('Switch to Buffer...'), gui.switch_buffer },
SEPARATOR,
{ title = L('Indentation'),
- menuitem('Tab width: 2', { set_indentation, 2 }),
- menuitem('Tab width: 3', { set_indentation, 3 }),
- menuitem('Tab width: 4', { set_indentation, 4 }),
- menuitem('Tab width: 8', { set_indentation, 8 }),
+ { 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 } },
SEPARATOR,
- menuitem('Toggle Use Tabs', { toggle_setting, 'use_tabs' }),
- menuitem('Convert Indentation', m_editing.convert_indentation),
+ { L('Toggle Use Tabs'), { utils.toggle_property, 'use_tabs' } },
+ { L('Convert Indentation'), m_editing.convert_indentation },
},
{ title = L('EOL Mode'),
- menuitem('CRLF', { set_eol_mode, 0 }),
- menuitem('CR', { set_eol_mode, 1 }),
- menuitem('LF', { set_eol_mode, 2 }),
+ { L('CRLF'), { utils.set_eol_mode, c.SC_EOL_CRLF } },
+ { L('CR'), { utils.set_eol_mode, c.SC_EOL_CR } },
+ { L('LF'), { utils.set_eol_mode, c.SC_EOL_LF } },
},
{ title = L('Encoding'),
- menuitem('UTF-8 Encoding', { set_encoding, 'UTF-8' }),
- menuitem('ASCII Encoding', { set_encoding, 'ASCII' }),
- menuitem('ISO-8859-1 Encoding', { set_encoding, 'ISO-8859-1' }),
- menuitem('MacRoman Encoding', { set_encoding, 'MacRoman' }),
- menuitem('UTF-16 Encoding', { set_encoding, 'UTF-16LE' }),
+ { 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-16 Encoding'), { utils.set_encoding, 'UTF-16LE' } },
},
SEPARATOR,
- menuitem('Select Lexer...', m_textadept.mime_types.select_lexer),
- menuitem('Refresh Syntax Highlighting',
- { _buffer.colourise, _buffer, 0, -1 }),
+ { L('Select Lexer...'), m_textadept.mime_types.select_lexer },
+ { L('Refresh Syntax Highlighting'), { _buffer.colourise, _buffer, 0, -1 } },
},
{ title = L('View'),
- menuitem('Next View', { gui.goto_view, 1, false }),
- menuitem('Previous View', { gui.goto_view, -1, false }),
+ { L('Next View'), { gui.goto_view, 1, false } },
+ { L('Previous View'), { gui.goto_view, -1, false } },
SEPARATOR,
- menuitem('Split View Vertical', { _view.split, _view }),
- menuitem('Split View Horizontal', { _view.split, _view, false }),
- menuitem('Unsplit View', function() view:unsplit() end),
- menuitem('Unsplit All Views', function() while view:unsplit() do end end),
- menuitem('Grow View',
- function() if view.size then view.size = view.size + 10 end end),
- menuitem('Shrink View',
- function() if view.size then view.size = view.size - 10 end end),
+ { L('Split View Vertical'), { _view.split, _view } },
+ { L('Split View Horizontal'), { _view.split, _view, false } },
+ { L('Unsplit View'), { _view.unsplit, _view } },
+ { L('Unsplit All Views'), utils.unsplit_all },
+ { L('Grow View'), { utils.grow, 10 } },
+ { L('Shrink View'), { utils.shrink, 10 } },
SEPARATOR,
- menuitem('Toggle Current Fold', function()
- local buffer = buffer
- buffer:toggle_fold(buffer:line_from_position(buffer.current_pos))
- end),
+ { L('Toggle Current Fold'), utils.toggle_current_fold },
SEPARATOR,
- menuitem('Toggle View EOL', { toggle_setting, 'view_eol' }),
- menuitem('Toggle Wrap Mode', { toggle_setting, 'wrap_mode' }),
- menuitem('Toggle Show Indent Guides',
- { toggle_setting, 'indentation_guides' }),
- menuitem('Toggle View Whitespace', { toggle_setting, 'view_ws' }),
- menuitem('Toggle Virtual Space',
- { toggle_setting, 'virtual_space_options', 2 }),
+ { L('Toggle View EOL'), { utils.toggle_property, 'view_eol' } },
+ { L('Toggle Wrap Mode'), { utils.toggle_property, 'wrap_mode' } },
+ { L('Toggle Show Indent Guides'),
+ { utils.toggle_property, 'indentation_guides' } },
+ { L('Toggle View Whitespace'), { utils.toggle_property, 'view_ws' } },
+ { L('Toggle Virtual Space'),
+ { utils.toggle_property, 'virtual_space_options',
+ c.SCVS_USERACCESSIBLE } },
SEPARATOR,
- menuitem('Zoom In', _buffer.zoom_in),
- menuitem('Zoom Out', _buffer.zoom_out),
- menuitem('Reset Zoom', function() buffer.zoom = 0 end),
+ { L('Zoom In'), _buffer.zoom_in },
+ { L('Zoom Out'), _buffer.zoom_out },
+ { L('Reset Zoom'), utils.reset_zoom },
},
{ title = L('Help'),
- menuitem('Show Manual',
- { open_webpage, _HOME..'/doc/manual/1_Introduction.html' }),
- menuitem('Show LuaDoc', { open_webpage, _HOME..'/doc/index.html' }),
+ { L('Show Manual'),
+ { utils.open_webpage, _HOME..'/doc/manual/1_Introduction.html' } },
+ { L('Show LuaDoc'), { utils.open_webpage, _HOME..'/doc/index.html' } },
SEPARATOR,
- menuitem('gtk-about', { gui.dialog, 'ok-msgbox', '--title', 'Textadept',
- '--informative-text', _RELEASE, '--no-cancel' }),
+ { L('gtk-about'), { gui.dialog, 'ok-msgbox', '--title', 'Textadept',
+ '--informative-text', _RELEASE, '--no-cancel' } },
},
}
@@ -342,6 +230,7 @@ context_menu = {
{ L('gtk-select-all'), _buffer.select_all }
}
+local key_shortcuts = {}
local menu_actions = {}
local contextmenu_actions = {}
@@ -356,14 +245,11 @@ local function read_menu_table(menu)
if menuitem.title then
gtkmenu[#gtkmenu + 1] = read_menu_table(menuitem)
else
- local label, f, k = menuitem[1], menuitem[2], menuitem[3]
+ local label, f = menuitem[1], menuitem[2]
local menu_id = #menu_actions + 1
- local key, mods = keys.get_gdk_key(k and k[1])
+ local key, mods = keys.get_gdk_key(key_shortcuts[get_id(f)])
gtkmenu[#gtkmenu + 1] = { label, menu_id, key, mods }
- if f then
- menu_actions[menu_id] = f
- if k then for _, key in ipairs(k) do keys[key] = f end end
- end
+ if f then menu_actions[menu_id] = f end
end
end
return gtkmenu
@@ -381,6 +267,8 @@ end
-- separator is created and no action table is required.
-- @see keys.get_gdk_key
function set_menubar(menubar)
+ key_shortcuts = {}
+ for key, f in pairs(keys) do key_shortcuts[get_id(f)] = key end
menu_actions = {}
local _menubar = {}
for i = 1, #menubar do
@@ -434,10 +322,10 @@ local function build_command_tables(menu, title, items, commands)
if menuitem.title then
build_command_tables(menuitem, menuitem.title, items, commands)
elseif menuitem[1] ~= 'separator' then
- local label, f, key_commands = menuitem[1], menuitem[2], menuitem[3]
+ local label, f = menuitem[1], menuitem[2]
if title then label = title..': '..label end
items[#items + 1] = label:gsub('_([^_])', '%1'):gsub('^gtk%-', '')
- items[#items + 1] = key_commands and key_commands[1] or ''
+ items[#items + 1] = key_shortcuts[get_id(f)] or ''
commands[#commands + 1] = f
end
end
diff --git a/modules/textadept/session.lua b/modules/textadept/session.lua
index f22307d6..bc697f2f 100644
--- a/modules/textadept/session.lua
+++ b/modules/textadept/session.lua
@@ -166,6 +166,34 @@ function save(filename)
end
end
+---
+-- Prompts the user for a Textadept session to load.
+function prompt_load()
+ local session_file = _SESSIONFILE or ''
+ local utf8_filename = gui.dialog('fileselect',
+ '--title', L('Load Session'),
+ '--with-directory',
+ session_file:match('.+[/\\]') or '',
+ '--with-file',
+ session_file:match('[^/\\]+$') or '',
+ '--no-newline')
+ if #utf8_filename > 0 then load(utf8_filename:iconv(_CHARSET, 'UTF-8')) end
+end
+
+---
+-- Prompts the user to save the current Textadept session to a file.
+function prompt_save()
+ local session_file = _SESSIONFILE or ''
+ local utf8_filename = gui.dialog('filesave',
+ '--title', L('Save Session'),
+ '--with-directory',
+ session_file:match('.+[/\\]') or '',
+ '--with-file',
+ session_file:match('[^/\\]+$') or '',
+ '--no-newline')
+ if #utf8_filename > 0 then save(utf8_filename:iconv(_CHARSET, 'UTF-8')) end
+end
+
events.connect(events.QUIT, function() if SAVE_ON_QUIT then save() end end, 1)
local function no_session() SAVE_ON_QUIT = false end