diff options
Diffstat (limited to 'core/ext')
-rw-r--r-- | core/ext/command_entry.lua | 47 | ||||
-rw-r--r-- | core/ext/find.lua | 361 | ||||
-rw-r--r-- | core/ext/key_commands.lua | 652 | ||||
-rw-r--r-- | core/ext/menu.lua | 518 |
4 files changed, 0 insertions, 1578 deletions
diff --git a/core/ext/command_entry.lua b/core/ext/command_entry.lua deleted file mode 100644 index 296244f4..00000000 --- a/core/ext/command_entry.lua +++ /dev/null @@ -1,47 +0,0 @@ --- Copyright 2007-2010 Mitchell mitchell<att>caladbolg.net. See LICENSE. - -local locale = _G.locale - -events.connect('command_entry_command', - function(command) -- execute a Lua command - local f, err = loadstring(command) - if err then error(err) end - gui.command_entry.focus() -- toggle focus to hide - f() - end) - -events.connect('command_entry_keypress', - function(code) - local ce = gui.command_entry - local KEYSYMS = keys.KEYSYMS - if KEYSYMS[code] == 'esc' then - ce.focus() -- toggle focus to hide - return true - elseif KEYSYMS[code] == '\t' then - local substring = ce.entry_text:match('[%w_.:]+$') or '' - local path, o, prefix = substring:match('^([%w_.:]-)([.:]?)([%w_]*)$') - local ret, tbl = pcall(loadstring('return ('..path..')')) - if not ret then tbl = getfenv(0) end - if type(tbl) ~= 'table' then return end - local cmpls = {} - for k in pairs(tbl) do - if type(k) == 'string' and k:find('^'..prefix) then - cmpls[#cmpls + 1] = k - end - end - if path == 'buffer' then - if o == ':' then - for f in pairs(_SCINTILLA.functions) do - if f:find('^'..prefix) then cmpls[#cmpls + 1] = f end - end - else - for p in pairs(_SCINTILLA.properties) do - if p:find('^'..prefix) then cmpls[#cmpls + 1] = p end - end - end - end - table.sort(cmpls) - ce.show_completions(cmpls) - return true - end - end) diff --git a/core/ext/find.lua b/core/ext/find.lua deleted file mode 100644 index eafef5ed..00000000 --- a/core/ext/find.lua +++ /dev/null @@ -1,361 +0,0 @@ --- Copyright 2007-2010 Mitchell mitchell<att>caladbolg.net. See LICENSE. - -local locale = _G.locale -local events = _G.events -local find = gui.find - -local lfs = require 'lfs' - -local MARK_FIND = 0 -local MARK_FIND_COLOR = 0x4D9999 -local previous_view - --- Text escape sequences with their associated characters. -local escapes = { - ['\\a'] = '\a', ['\\b'] = '\b', ['\\f'] = '\f', ['\\n'] = '\n', - ['\\r'] = '\r', ['\\t'] = '\t', ['\\v'] = '\v', ['\\\\'] = '\\' -} - --- Finds and selects text in the current buffer. --- @param text The text to find. --- @param next Flag indicating whether or not the search direction is forward. --- @param flags Search flags. This is a number mask of 4 flags: match case (2), --- whole word (4), Lua pattern (8), and in files (16) joined with binary OR. --- If nil, this is determined based on the checkboxes in the find box. --- @param nowrap Flag indicating whether or not the search won't wrap. --- @param wrapped Utility flag indicating whether or not the search has wrapped --- for displaying useful statusbar information. This flag is used and set --- internally, and should not be set otherwise. --- @return position of the found text or -1 -local function find_(text, next, flags, nowrap, wrapped) - if #text == 0 then return end - local buffer = buffer - local first_visible_line = buffer.first_visible_line -- for 'no results found' - - local increment - if buffer.current_pos == buffer.anchor then - increment = 0 - elseif not wrapped then - increment = next and 1 or -1 - end - - if not flags then - local find, c = find, _SCINTILLA.constants - flags = 0 - if find.match_case then flags = flags + c.SCFIND_MATCHCASE end - if find.whole_word then flags = flags + c.SCFIND_WHOLEWORD end - if find.lua then flags = flags + 8 end - if find.in_files then flags = flags + 16 end - end - - local result - find.captures = nil - - if flags < 8 then - buffer:goto_pos(buffer[next and 'current_pos' or 'anchor'] + increment) - buffer:search_anchor() - if next then - result = buffer:search_next(flags, text) - else - result = buffer:search_prev(flags, text) - end - if result ~= -1 then buffer:scroll_caret() end - - elseif flags < 16 then -- lua pattern search (forward search only) - text = text:gsub('\\[abfnrtv\\]', escapes) - local buffer_text = buffer:get_text(buffer.length) - local results = { buffer_text:find(text, buffer.anchor + increment) } - if #results > 0 then - result = results[1] - find.captures = { unpack(results, 3) } - buffer:set_sel(results[2], result - 1) - else - result = -1 - end - - else -- find in files - local utf8_dir = - gui.dialog('fileselect', - '--title', locale.FIND_IN_FILES_TITLE, - '--select-only-directories', - '--with-directory', - (buffer.filename or ''):match('^.+[/\\]') or '', - '--no-newline') - if #utf8_dir > 0 then - if not find.lua then text = text:gsub('([().*+?^$%%[%]-])', '%%%1') end - if not find.match_case then text = text:lower() end - if find.whole_word then text = '[^%W_]'..text..'[^%W_]' end - local match_case = find.match_case - local whole_word = find.whole_word - local format = string.format - local matches = { 'Find: '..text } - function search_file(file) - local line_num = 1 - for line in io.lines(file) do - local optimized_line = line - if not match_case then optimized_line = line:lower() end - if whole_word then optimized_line = ' '..line..' ' end - if string.find(optimized_line, text) then - file = file:iconv('UTF-8', _CHARSET) - matches[#matches + 1] = format('%s:%s:%s', file, line_num, line) - end - line_num = line_num + 1 - end - end - function search_dir(directory) - for file in lfs.dir(directory) do - if not file:find('^%.%.?$') then -- ignore . and .. - local path = directory..'/'..file - local type = lfs.attributes(path).mode - if type == 'directory' then - search_dir(path) - elseif type == 'file' then - search_file(path) - end - end - end - end - local dir = utf8_dir:iconv(_CHARSET, 'UTF-8') - search_dir(dir) - if #matches == 1 then matches[2] = locale.FIND_NO_RESULTS end - matches[#matches + 1] = '' - if buffer._type ~= locale.FIND_FILES_FOUND_BUFFER then - previous_view = view - end - gui._print(locale.FIND_FILES_FOUND_BUFFER, table.concat(matches, '\n')) - end - return - end - - if result == -1 and not nowrap and not wrapped then -- wrap the search - local anchor, pos = buffer.anchor, buffer.current_pos - if next or flags >= 8 then - buffer:goto_pos(0) - else - buffer:goto_pos(buffer.length) - end - gui.statusbar_text = locale.FIND_SEARCH_WRAPPED - result = find_(text, next, flags, true, true) - if result == -1 then - gui.statusbar_text = locale.FIND_NO_RESULTS - buffer:line_scroll(0, first_visible_line) - buffer:goto_pos(anchor) - end - return result - elseif result ~= -1 and not wrapped then - gui.statusbar_text = '' - end - - return result -end -events.connect('find', find_) - --- Finds and selects text incrementally in the current buffer from a start --- point. --- Flags other than SCFIND_MATCHCASE are ignored. --- @param text The text to find. -local function find_incremental(text) - local c = _SCINTILLA.constants - local flags = find.match_case and c.SCFIND_MATCHCASE or 0 - --if find.lua then flags = flags + 8 end - buffer:goto_pos(find.incremental_start or 0) - find_(text, true, flags) -end - --- LuaDoc is in core/.find.lua. -function find.find_incremental() - find.incremental = true - find.incremental_start = buffer.current_pos - gui.command_entry.entry_text = '' - gui.command_entry.focus() -end - -events.connect('command_entry_keypress', - function(code) - if find.incremental then - if code == 0xff1b then -- escape - find.incremental = nil - elseif code < 256 or code == 0xff08 then -- character or backspace - local text = gui.command_entry.entry_text - if code == 0xff08 then - find_incremental(text:sub(1, -2)) - else - find_incremental(text..string.char(code)) - end - end - end - end, 1) -- place before command_entry.lua's handler (if necessary) - -events.connect('command_entry_command', - function(text) -- 'find next' for incremental search - if find.incremental then - find.incremental_start = buffer.current_pos + 1 - find_incremental(text) - return true - end - end, 1) -- place before command_entry.lua's handler (if necessary) - --- Replaces found text. --- 'find_' is called first, to select any found text. The selected text is then --- replaced by the specified replacement text. --- This function ignores 'Find in Files'. --- @param rtext The text to replace found text with. It can contain both Lua --- capture items (%n where 1 <= n <= 9) for Lua pattern searches and %() --- sequences for embedding Lua code for any search. --- @see find -local function replace(rtext) - if #buffer:get_sel_text() == 0 then return end - if find.in_files then find.in_files = false end - local buffer = buffer - buffer:target_from_selection() - rtext = rtext:gsub('%%%%', '\\037') -- escape '%%' - if find.captures then - for i, v in ipairs(find.captures) do - v = v:gsub('%%', '%%%%') -- escape '%' for gsub - rtext = rtext:gsub('%%'..i, v) - end - end - local ret, rtext = pcall(rtext.gsub, rtext, '%%(%b())', - function(code) - local ret, val = pcall(loadstring('return '..code)) - if not ret then - gui.dialog('ok-msgbox', - '--title', locale.FIND_ERROR_DIALOG_TITLE, - '--text', locale.FIND_ERROR_DIALOG_TEXT, - '--informative-text', val:gsub('"', '\\"'), - '--no-cancel') - error() - end - return val - end) - if ret then - rtext = rtext:gsub('\\037', '%%') -- unescape '%' - buffer:replace_target(rtext:gsub('\\[abfnrtv\\]', escapes)) - buffer:goto_pos(buffer.target_end) -- 'find' text after this replacement - else - -- Since find is called after replace returns, have it 'find' the current - -- text again, rather than the next occurance so the user can fix the error. - buffer:goto_pos(buffer.current_pos) - end -end -events.connect('replace', replace) - --- Replaces all found text. --- If any text is selected, all found text in that selection is replaced. --- This function ignores 'Find in Files'. --- @param ftext The text to find. --- @param rtext The text to replace found text with. --- @param flags The number mask identical to the one in 'find'. --- @see find -local function replace_all(ftext, rtext, flags) - if #ftext == 0 then return end - if find.in_files then find.in_files = false end - local buffer = buffer - buffer:begin_undo_action() - local count = 0 - if #buffer:get_sel_text() == 0 then - buffer:goto_pos(0) - while(find_(ftext, true, flags, true) ~= -1) do - replace(rtext) - count = count + 1 - end - else - local anchor, current_pos = buffer.anchor, buffer.current_pos - local s, e = anchor, current_pos - if s > e then s, e = e, s end - buffer:insert_text(e, '\n') - local end_marker = - buffer:marker_add(buffer:line_from_position(e + 1), MARK_FIND) - buffer:goto_pos(s) - local pos = find_(ftext, true, flags, true) - while pos ~= -1 and - pos < buffer:position_from_line( - buffer:marker_line_from_handle(end_marker)) do - replace(rtext) - count = count + 1 - pos = find_(ftext, true, flags, true) - end - e = buffer:position_from_line(buffer:marker_line_from_handle(end_marker)) - buffer:goto_pos(e) - buffer:delete_back() -- delete '\n' added - if s == current_pos then anchor = e - 1 else current_pos = e - 1 end - buffer:set_sel(anchor, current_pos) - buffer:marker_delete_handle(end_marker) - end - gui.statusbar_text = - string.format(locale.FIND_REPLACEMENTS_MADE, tostring(count)) - buffer:end_undo_action() -end -events.connect('replace_all', replace_all) - --- When the user double-clicks a found file, go to the line in the file the text --- was found at. --- @param pos The position of the caret. --- @param line_num The line double-clicked. -local function goto_file(pos, line_num) - if buffer._type == locale.FIND_FILES_FOUND_BUFFER then - line = buffer:get_line(line_num) - local file, file_line_num = line:match('^(.+):(%d+):.+$') - if file and file_line_num then - buffer:marker_delete_all(MARK_FIND) - buffer:marker_set_back(MARK_FIND, MARK_FIND_COLOR) - buffer:marker_add(line_num, MARK_FIND) - buffer:goto_pos(buffer.current_pos) - if #_VIEWS == 1 then - _, previous_view = view:split(false) -- horizontal - else - local clicked_view = view - if previous_view then previous_view:focus() end - if buffer._type == locale.FIND_FILES_FOUND_BUFFER then - -- there are at least two find in files views; find one of those views - -- that the file was not selected from and focus it - for _, v in ipairs(_VIEWS) do - if v ~= clicked_view then - previous_view = v - v:focus() - break - end - end - end - end - io.open_file(file) - buffer:ensure_visible_enforce_policy(file_line_num - 1) - buffer:goto_line(file_line_num - 1) - end - end -end -events.connect('double_click', goto_file) - --- LuaDoc is in core/.find.lua. -function find.goto_file_in_list(next) - local orig_view = view - for _, buffer in ipairs(_BUFFERS) do - if buffer._type == locale.FIND_FILES_FOUND_BUFFER then - for _, view in ipairs(_VIEWS) do - if view.doc_pointer == buffer.doc_pointer then - view:focus() - local orig_line = buffer:line_from_position(buffer.current_pos) - local line = orig_line - while true do - line = line + (next and 1 or -1) - if line > buffer.line_count - 1 then line = 0 end - if line < 0 then line = buffer.line_count - 1 end - if line == orig_line then -- prevent infinite loops - orig_view:focus() - return - end - if buffer:get_line(line):match('^(.+):(%d+):.+$') then - buffer:goto_line(line) - goto_file(buffer.current_pos, line) - return - end - end - end - end - end - end -end - -if buffer then buffer:marker_set_back(MARK_FIND, MARK_FIND_COLOR) end -events.connect('view_new', - function() buffer:marker_set_back(MARK_FIND, MARK_FIND_COLOR) end) diff --git a/core/ext/key_commands.lua b/core/ext/key_commands.lua deleted file mode 100644 index 310db7aa..00000000 --- a/core/ext/key_commands.lua +++ /dev/null @@ -1,652 +0,0 @@ --- Copyright 2007-2010 Mitchell mitchell<att>caladbolg.net. See LICENSE. - -local locale = _G.locale -local events = _G.events - ---- --- Manages and defines key commands in Textadept. --- This set of key commands is pretty standard among other text editors. -module('keys', package.seeall) - --- Markdown: --- ## Overview --- --- Key commands are defined in the global table `keys`. Each key-value pair in --- `keys` consists of either: --- --- * A string representing a key command and an associated action table. --- * A string language name and its associated `keys`-like table. --- * A string style name and its associated `keys`-like table. --- * A string representing a key command and its associated `keys`-like table. --- (This is a keychain sequence.) --- --- A key command string is built from a combination of the `CTRL`, `SHIFT`, --- `ALT`, and `ADD` constants as well as the pressed key itself. The value of --- `ADD` is inserted between each of `CTRL`, `SHIFT`, `ALT`, and the key. --- For example: --- --- -- keys.lua: --- CTRL = 'Ctrl' --- SHIFT = 'Shift' --- ALT = 'Alt' --- ADD = '+' --- -- pressing control, shift, alt and 'a' yields: 'Ctrl+Shift+Alt+A' --- --- For key values less than 255, Lua's [`string.char()`][string_char] is used to --- determine the key's string representation. Otherwise, the --- [`KEYSYMS`][keysyms] lookup table is used. --- --- [string_char]: http://www.lua.org/manual/5.1/manual.html#pdf-string.char --- [keysyms]: ../modules/keys.html#KEYSYMS --- --- An action table is a table consisting of either: --- --- * A Lua function followed by a list of arguments to pass to that function. --- * A string representing a [buffer][buffer] or [view][view] function followed --- by its respective `'buffer'` or `'view'` string and then any arguments to --- pass to the resulting function. --- --- `buffer.`_`function`_ by itself cannot be used because at the time of --- evaluation, `buffer.`_`function`_ would apply only to the current --- buffer, not for all buffers. By using this string reference system, the --- correct `buffer.`_`function`_ will be evaluated every time. The same --- applies to `view`. --- --- [buffer]: ../modules/buffer.html --- [view]: ../modules/view.html --- --- Language names are the names of the lexer files in `lexers/` such as `cpp` --- and `lua`. Style names are different lexer styles, most of which are in --- `lexers/lexer.lua`; examples are `whitespace`, `comment`, and `string`. --- --- Key commands can be chained like in Emacs using keychain sequences. By --- default, the `Esc` key cancels the current keychain, but it can be redefined --- by setting the `keys.clear_sequence` field. Naturally, the clear sequence --- cannot be chained. --- --- ## Settings --- --- * `SCOPES_ENABLED`: Flag indicating whether scopes/styles can be used for key --- commands. --- * `CTRL`: The string representing the Control key. --- * `SHIFT`: The string representing the Shift key. --- * `ALT`: The string representing the Alt key (the Apple key on Mac OSX). --- * `ADD`: The string representing used to join together a sequence of Control, --- Shift, or Alt modifier keys. --- --- ## Key Command Precedence --- --- When searching for a key command to execute in the `keys` table, key commands --- in the current style have priority, followed by the ones in the current lexer, --- and finally the ones in the global table. --- --- ## Example --- --- keys = { --- ['ctrl+f'] = { 'char_right', 'buffer' }, --- ['ctrl+b'] = { 'char_left', 'buffer' }, --- lua = { --- ['ctrl+c'] = { 'add_text', 'buffer', '-- ' }, --- whitespace = { --- ['ctrl+f'] = { function() print('whitespace') end } --- } --- } --- } --- --- The first two key commands are global and call `buffer:char_right()` and --- `buffer:char_left()` respectively. The last two commands apply only in the --- Lua lexer with the very last one only being available in Lua's `whitespace` --- style. If `ctrl+f` is pressed when the current style is `whitespace` in the --- `lua` lexer, the global key command with the same shortcut is overriden and --- `whitespace` is printed to standard out. --- --- ## Problems --- --- All Lua functions must be defined BEFORE they are reference in key commands. --- Therefore, any module containing key commands should be loaded after all --- other modules, whose functions are being referenced, have been loaded. --- --- ## Configuration --- --- It is not recommended to edit Textadept's `core/ext/key_commands.lua`. You --- can either override or add to default key commands in your --- `~/.textadept/key_commands.lua` or `require` a separate module in your --- `~/.textadept/init.lua` instead of `ext/key_commands`. - --- Windows and Linux key commands are listed in the first block. --- Mac OSX key commands are listed in the second block. - --- settings -local SCOPES_ENABLED = true -local ADD = '' -local CTRL = 'c'..ADD -local SHIFT = 's'..ADD -local ALT = 'a'..ADD --- end settings - -local keys = keys -local b, v = 'buffer', 'view' -local gui = gui - --- CTRL = 'c' --- SHIFT = 's' --- ALT = 'a' --- ADD = '' --- Control, Shift, Alt, and 'a' = 'caA' --- Control, Shift, Alt, and '\t' = 'csa\t' - -if not MAC then - -- Windows and Linux key commands. - - --[[ - C: D H I J K M U - A: A B C D E F G H J K L M N P R S T U V W X Y Z - CS: A B C D G H I J K L M N O Q T U V X Y Z - SA: A B C D E F G H I J K L M N O P Q R S T U V W X Y Z - CA: A B C D E F G H J K L M N O Q R S T U V W X Y Z - CSA: A B C D E F G H J K L M N O P Q R S T U V W X Y Z - ]]-- - - keys.clear_sequence = 'esc' - - keys.ct = {} -- Textadept command chain - - -- File - local m_session = _m.textadept.session - keys.cn = { new_buffer } - keys.co = { io.open_file } - -- TODO: { 'reload', b } - keys.cs = { 'save', b } - keys.cS = { 'save_as', b } - keys.cw = { 'close', b } - keys.cW = { io.close_all } - -- TODO: { m_session.load } after prompting with open dialog - -- TODO: { m_session.save } after prompting with save dialog - keys.aq = { quit } - - -- Edit - local m_editing = _m.textadept.editing - keys.cz = { 'undo', b } - keys.cy = { 'redo', b } - keys.cx = { 'cut', b } - keys.cc = { 'copy', b } - keys.cv = { 'paste', b } - -- Delete is delete. - keys.ca = { 'select_all', b } - keys.ce = { m_editing.match_brace } - keys.cE = { m_editing.match_brace, 'select' } - keys['c\n'] = { m_editing.autocomplete_word, '%w_' } - keys['c\n\r'] = { m_editing.autocomplete_word, '%w_' } -- win32 - keys.cq = { m_editing.block_comment } - -- TODO: { m_editing.current_word, 'delete' } - -- TODO: { m_editing.transpose_chars } - -- TODO: { m_editing.squeeze } - -- TODO: { m_editing.convert_indentation } - -- TODO: { m_editing.smart_cutcopy } - -- TODO: { m_editing.smart_cutcopy, 'copy' } - keys.ac = { -- enClose in... - t = { m_editing.enclose, 'tag' }, - T = { m_editing.enclose, 'single_tag' }, - ['"'] = { m_editing.enclose, 'dbl_quotes' }, - ["'"] = { m_editing.enclose, 'sng_quotes' }, - ['('] = { m_editing.enclose, 'parens' }, - ['['] = { m_editing.enclose, 'brackets' }, - ['{'] = { m_editing.enclose, 'braces' }, - c = { m_editing.enclose, 'chars' }, - } - keys.as = { -- select in... - t = { m_editing.select_enclosed, 'tags' }, - ['"'] = { m_editing.select_enclosed, 'dbl_quotes' }, - ["'"] = { m_editing.select_enclosed, 'sng_quotes' }, - ['('] = { m_editing.select_enclosed, 'parens' }, - ['['] = { m_editing.select_enclosed, 'brackets' }, - ['{'] = { m_editing.select_enclosed, 'braces' }, - w = { m_editing.current_word, 'select' }, - l = { m_editing.select_line }, - p = { m_editing.select_paragraph }, - b = { m_editing.select_indented_block }, - s = { m_editing.select_scope }, - g = { m_editing.grow_selection, 1 }, - } - - -- Search - keys.cf = { gui.find.focus } -- find/replace - keys['f3'] = { gui.find.find_next } - -- Find Next is an when find pane is focused. - -- Find Prev is ap when find pane is focused. - -- Replace is ar when find pane is focused. - keys.cF = { gui.find.find_incremental } - -- Find in Files is ai when find pane is focused. - -- TODO: { gui.find.goto_file_in_list, true } - -- TODO: { gui.find.goto_file_in_list, false } - keys.cg = { m_editing.goto_line } - - -- Tools - keys['f2'] = { gui.command_entry.focus } - -- Run - local m_run = _m.textadept.run - keys.cr = { m_run.run } - keys.cR = { m_run.compile } - -- Snippets - local m_snippets = _m.textadept.snippets - keys['\t'] = { m_snippets.insert } - keys['s\t'] = { m_snippets.prev } - keys.cai = { m_snippets.cancel_current } - keys.caI = { m_snippets.list } - keys.ai = { m_snippets.show_style } - - -- Buffers - keys.cb = { gui.switch_buffer } - keys['c\t'] = { 'goto_buffer', v, 1, false } - keys['cs\t'] = { 'goto_buffer', v, -1, false } - local function toggle_setting(setting) - local state = buffer[setting] - if type(state) == 'boolean' then - buffer[setting] = not state - elseif type(state) == 'number' then - buffer[setting] = buffer[setting] == 0 and 1 or 0 - end - events.emit('update_ui') -- for updating statusbar - end - keys.ct.v = { - e = { toggle_setting, 'view_eol' }, - w = { toggle_setting, 'wrap_mode' }, - i = { toggle_setting, 'indentation_guides' }, - ['\t'] = { toggle_setting, 'use_tabs' }, - [' '] = { toggle_setting, 'view_ws' }, - } - keys.cl = { _m.textadept.mime_types.select_lexer } - keys['f5'] = { 'colourise', b, 0, -1 } - - -- Views - keys.cav = { - n = { gui.goto_view, 1, false }, - p = { gui.goto_view, -1, false }, - S = { 'split', v }, -- vertical - s = { 'split', v, false }, -- horizontal - w = { function() view:unsplit() return true end }, - W = { function() while view:unsplit() do end end }, - -- TODO: { function() view.size = view.size + 10 end } - -- TODO: { function() view.size = view.size - 10 end } - } - keys.c0 = { function() buffer.zoom = 0 end } - - -- Miscellaneous not in standard menu. - -- Recent files. - local RECENT_FILES = 1 - events.connect('user_list_selection', - function(type, text) - if type == RECENT_FILES then io.open_file(text) end - end) - keys.ao = { - function() - local buffer = buffer - local files = {} - for _, filename in ipairs(io.recent_files) do - table.insert(files, 1, filename) - end - local sep = buffer.auto_c_separator - buffer.auto_c_separator = ('|'):byte() - buffer:user_list_show(RECENT_FILES, table.concat(files, '|')) - buffer.auto_c_separator = sep - end - } - -else - -- Mac OSX key commands - - --[[ - C: J M U W X Z - A: D E H J K L U Y - CS: C D G H I J K L M O Q S T U V W X Y Z - SA: A B C D H I J K L M N O Q R T U V X Y - CA: A C E J K L M N O Q R S T U V W X Y Z - CSA: A C D E H J K L M N O P Q R S T U V W X Y Z - ]]-- - - keys.clear_sequence = 'aesc' - - keys.at = {} -- Textadept command chain - - -- File - local m_session = _m.textadept.session - keys.an = { new_buffer } - keys.ao = { io.open_file } - -- TODO: { 'reload', b } - keys.as = { 'save', b } - keys.aS = { 'save_as', b } - keys.aw = { 'close', b } - keys.aW = { io.close_all } - -- TODO: { m_session.load } after prompting with open dialog - -- TODO: { m_session.save } after prompting with save dialog - keys.aq = { quit } - - -- Edit - local m_editing = _m.textadept.editing - keys.az = { 'undo', b } - keys.aZ = { 'redo', b } - keys.ax = { 'cut', b } - keys.ac = { 'copy', b } - keys.av = { 'paste', b } - -- Delete is delete. - keys.aa = { 'select_all', b } - keys.cm = { m_editing.match_brace } - keys.aE = { m_editing.match_brace, 'select' } - keys.esc = { m_editing.autocomplete_word, '%w_' } - keys.cq = { m_editing.block_comment } - -- TODO: { m_editing.current_word, 'delete' } - keys.ct = { m_editing.transpose_chars } - -- TODO: { m_editing.squeeze } - -- TODO: { m_editing.convert_indentation } - keys.ck = { m_editing.smart_cutcopy } - -- TODO: { m_editing.smart_cutcopy, 'copy' } - keys.cy = { 'paste', b } - keys.cc = { -- enClose in... - t = { m_editing.enclose, 'tag' }, - T = { m_editing.enclose, 'single_tag' }, - ['"'] = { m_editing.enclose, 'dbl_quotes' }, - ["'"] = { m_editing.enclose, 'sng_quotes' }, - ['('] = { m_editing.enclose, 'parens' }, - ['['] = { m_editing.enclose, 'brackets' }, - ['{'] = { m_editing.enclose, 'braces' }, - c = { m_editing.enclose, 'chars' }, - } - keys.cs = { -- select in... - e = { m_editing.select_enclosed }, - t = { m_editing.select_enclosed, 'tags' }, - ['"'] = { m_editing.select_enclosed, 'dbl_quotes' }, - ["'"] = { m_editing.select_enclosed, 'sng_quotes' }, - ['('] = { m_editing.select_enclosed, 'parens' }, - ['['] = { m_editing.select_enclosed, 'brackets' }, - ['{'] = { m_editing.select_enclosed, 'braces' }, - w = { m_editing.current_word, 'select' }, - l = { m_editing.select_line }, - p = { m_editing.select_paragraph }, - b = { m_editing.select_indented_block }, - s = { m_editing.select_scope }, - g = { m_editing.grow_selection, 1 }, - } - - -- Search - keys.af = { gui.find.focus } -- find/replace - keys.ag = { gui.find.find_next } - keys.aG = { gui.find.find_prev } - keys.ar = { gui.find.replace } - keys.ai = { gui.find.find_incremental } - keys.aF = { - function() - gui.find.in_files = true - gui.find.focus() - end - } - keys.cag = { gui.find.goto_file_in_list, true } - keys.caG = { gui.find.goto_file_in_list, false } - keys.cg = { m_editing.goto_line } - - -- Tools - keys['f2'] = { gui.command_entry.focus } - -- Run - local m_run = _m.textadept.run - keys.cr = { m_run.run } - keys.cR = { m_run.compile } - -- Snippets - local m_snippets = _m.textadept.snippets - keys['\t'] = { m_snippets.insert } - keys['s\t'] = { m_snippets.prev } - keys.cai = { m_snippets.cancel_current } - keys.caI = { m_snippets.list } - keys.ci = { m_snippets.show_style } - - -- Buffers - keys.ab = { gui.switch_buffer } - keys['c\t'] = { 'goto_buffer', v, 1, false } - keys['cs\t'] = { 'goto_buffer', v, -1, false } - local function toggle_setting(setting) - local state = buffer[setting] - if type(state) == 'boolean' then - buffer[setting] = not state - elseif type(state) == 'number' then - buffer[setting] = buffer[setting] == 0 and 1 or 0 - end - events.emit('update_ui') -- for updating statusbar - end - keys.at.v = { - e = { toggle_setting, 'view_eol' }, - w = { toggle_setting, 'wrap_mode' }, - i = { toggle_setting, 'indentation_guides' }, - ['\t'] = { toggle_setting, 'use_tabs' }, - [' '] = { toggle_setting, 'view_ws' }, - } - keys.cl = { _m.textadept.mime_types.select_lexer } - keys['f5'] = { 'colourise', b, 0, -1 } - - -- Views - keys.cv = { - n = { gui.goto_view, 1, false }, - p = { gui.goto_view, -1, false }, - S = { 'split', v }, -- vertical - s = { 'split', v, false }, -- horizontal - w = { function() view:unsplit() return true end }, - W = { function() while view:unsplit() do end end }, - -- TODO: { function() view.size = view.size + 10 end } - -- TODO: { function() view.size = view.size - 10 end } - } - keys.c0 = { function() buffer.zoom = 0 end } - - -- Miscellaneous not in standard menu. - -- Recent files. - local RECENT_FILES = 1 - events.connect('user_list_selection', - function(type, text) - if type == RECENT_FILES then io.open_file(text) end - end) - keys.co = { - function() - local buffer = buffer - local files = {} - for _, filename in ipairs(io.recent_files) do - table.insert(files, 1, filename) - end - local sep = buffer.auto_c_separator - buffer.auto_c_separator = ('|'):byte() - buffer:user_list_show(RECENT_FILES, table.concat(files, '|')) - buffer.auto_c_separator = sep - end - } - - -- Movement/selection commands - keys.cf = { 'char_right', b } - keys.cF = { 'char_right_extend', b } - keys.caf = { 'word_right', b } - keys.caF = { 'word_right_extend', b } - keys.cb = { 'char_left', b } - keys.cB = { 'char_left_extend', b } - keys.cab = { 'word_left', b } - keys.caB = { 'word_left_extend', b } - keys.cn = { 'line_down', b } - keys.cN = { 'line_down_extend', b } - keys.cp = { 'line_up', b } - keys.cP = { 'line_up_extend', b } - keys.ca = { 'vc_home', b } - keys.cA = { 'home_extend', b } - keys.ce = { 'line_end', b } - keys.cE = { 'line_end_extend', b } - keys.ch = { 'delete_back', b } - keys.cah = { 'del_word_left', b } - keys.cd = { 'clear', b } - keys.cad = { 'del_word_right', b } -end - -user_dofile('key_commands.lua') -- load user key commands - --- Do not edit below this line. - --- optimize for speed -local string = _G.string -local string_char = string.char -local string_format = string.format -local pcall = _G.pcall -local ipairs = _G.ipairs -local next = _G.next -local type = _G.type -local unpack = _G.unpack -local MAC = _G.MAC - ---- --- Lookup table for key values higher than 255. --- If a key value given to 'keypress' is higher than 255, this table is used to --- return a string representation of the key if it exists. --- @class table --- @name KEYSYMS -KEYSYMS = { -- from <gdk/gdkkeysyms.h> - [65056] = '\t', -- backtab; will be 'shift'ed - [65288] = '\b', - [65289] = '\t', - [65293] = '\n', - [65307] = 'esc', - [65535] = 'del', - [65360] = 'home', - [65361] = 'left', - [65362] = 'up', - [65363] = 'right', - [65364] = 'down', - [65365] = 'pup', - [65366] = 'pdown', - [65367] = 'end', - [65379] = 'ins', - [65470] = 'f1', [65471] = 'f2', [65472] = 'f3', [65473] = 'f4', - [65474] = 'f5', [65475] = 'f6', [65476] = 'f7', [65477] = 'f8', - [65478] = 'f9', [65479] = 'f10', [65480] = 'f11', [65481] = 'f12', -} - --- The current key sequence. -local keychain = {} - --- Clears the current key sequence. -local function clear_key_sequence() - keychain = {} - gui.statusbar_text = '' -end - --- Helper function that gets commands associated with the current keychain from --- 'keys'. --- If the current item in the keychain is part of a chain, throw an error value --- of -1. This way, pcall will return false and -1, where the -1 can easily and --- efficiently be checked rather than using a string error message. -local function try_get_cmd(active_table) - for _, key_seq in ipairs(keychain) do active_table = active_table[key_seq] end - if #active_table == 0 and next(active_table) then - gui.statusbar_text = locale.KEYCHAIN..table.concat(keychain, ' ') - error(-1, 0) - else - local func = active_table[1] - if type(func) == 'function' then - return func, { unpack(active_table, 2) } - elseif type(func) == 'string' then - local object = active_table[2] - if object == 'buffer' then - return buffer[func], { buffer, unpack(active_table, 3) } - elseif object == 'view' then - return view[func], { view, unpack(active_table, 3) } - end - else - error(locale.KEYS_UNKNOWN_COMMAND..tostring(func)) - end - end -end - --- Tries to get a key command based on the lexer and current scope. -local function try_get_cmd1(keys, lexer, scope) - return try_get_cmd(keys[lexer][scope]) -end - --- Tries to get a key command based on the lexer. -local function try_get_cmd2(keys, lexer) - return try_get_cmd(keys[lexer]) -end - --- Tries to get a global key command. -local function try_get_cmd3(keys) - return try_get_cmd(keys) -end - --- Handles Textadept keypresses. --- It is called every time a key is pressed, and based on lexer and scope, --- executes a command. The command is looked up in the global 'keys' key --- command table. --- @return whatever the executed command returns, true by default. A true --- return value will tell Textadept not to handle the key afterwords. -local function keypress(code, shift, control, alt) - local buffer = buffer - local key - --print(code, string.char(code)) - if code < 256 then - key = string_char(code) - shift = false -- for printable characters, key is upper case - if MAC and not shift and not control and not alt then - local ch = string_char(code) - -- work around native GTK-OSX's handling of Alt key - if ch:find('[%p%d]') and #keychain == 0 then - if buffer.anchor ~= buffer.current_pos then buffer:delete_back() end - buffer:add_text(ch) - events.emit('char_added', code) - return true - end - end - else - if not KEYSYMS[code] then return end - key = KEYSYMS[code] - end - control = control and CTRL or '' - shift = shift and SHIFT or '' - alt = alt and ALT or '' - local key_seq = string_format('%s%s%s%s', control, shift, alt, key) - - if #keychain > 0 and key_seq == keys.clear_sequence then - clear_key_sequence() - return true - end - - local lexer = buffer:get_lexer_language() - keychain[#keychain + 1] = key_seq - local ret, func, args - if SCOPES_ENABLED then - local style = buffer.style_at[buffer.current_pos] - local scope = buffer:get_style_name(style) - --print(key_seq, 'Lexer: '..lexer, 'Scope: '..scope) - ret, func, args = pcall(try_get_cmd1, keys, lexer, scope) - end - if not ret and func ~= -1 then - ret, func, args = pcall(try_get_cmd2, keys, lexer) - end - if not ret and func ~= -1 then - ret, func, args = pcall(try_get_cmd3, keys) - end - - if ret then - clear_key_sequence() - if type(func) == 'function' then - local ret, retval = pcall(func, unpack(args)) - if ret then - if type(retval) == 'boolean' then return retval end - else - error(retval) - end - end - return true - else - -- Clear key sequence because it's not part of a chain. - -- (try_get_cmd throws error number -1.) - if func ~= -1 then - local size = #keychain - 1 - clear_key_sequence() - if size > 0 then -- previously in a chain - gui.statusbar_text = locale.KEYS_INVALID - return true - end - else - return true - end - end -end -events.connect('keypress', keypress, 1) diff --git a/core/ext/menu.lua b/core/ext/menu.lua deleted file mode 100644 index 60e5679c..00000000 --- a/core/ext/menu.lua +++ /dev/null @@ -1,518 +0,0 @@ --- Copyright 2007-2010 Mitchell mitchell<att>caladbolg.net. See LICENSE. - -local locale = _G.locale -local events = _G.events - ---- --- Provides dynamic menus for Textadept. --- This module, like ext/key_commands, should be 'require'ed last. -module('menu', package.seeall) - -local gui = gui -local l = locale -local gtkmenu = gui.gtkmenu - -local SEPARATOR = 'separator' -local ID = { - SEPARATOR = 0, - -- File - NEW = 101, - OPEN = 102, - RELOAD = 103, - SAVE = 104, - SAVEAS = 105, - CLOSE = 106, - CLOSE_ALL = 107, - LOAD_SESSION = 108, - SAVE_SESSION = 109, - QUIT = 110, - -- Edit - UNDO = 201, - REDO = 202, - CUT = 203, - COPY = 204, - PASTE = 205, - DELETE = 206, - SELECT_ALL = 207, - MATCH_BRACE = 208, - SELECT_TO_BRACE = 209, - COMPLETE_WORD = 210, - DELETE_WORD = 211, - TRANSPOSE_CHARACTERS = 212, - SQUEEZE = 213, - JOIN_LINES = 245, - CONVERT_INDENTATION = 216, - ENCLOSE_IN_HTML_TAGS = 224, - ENCLOSE_IN_HTML_SINGLE_TAG = 225, - ENCLOSE_IN_DOUBLE_QUOTES = 226, - ENCLOSE_IN_SINGLE_QUOTES = 227, - ENCLOSE_IN_PARENTHESES = 228, - ENCLOSE_IN_BRACKETS = 229, - ENCLOSE_IN_BRACES = 230, - ENCLOSE_IN_CHARACTER_SEQUENCE = 231, - GROW_SELECTION = 232, - SELECT_IN_HTML_TAG = 234, - SELECT_IN_DOUBLE_QUOTE = 235, - SELECT_IN_SINGLE_QUOTE = 236, - SELECT_IN_PARENTHESIS = 237, - SELECT_IN_BRACKET = 238, - SELECT_IN_BRACE = 239, - SELECT_IN_WORD = 240, - SELECT_IN_LINE = 241, - SELECT_IN_PARAGRAPH = 242, - SELECT_IN_INDENTED_BLOCK = 243, - SELECT_IN_SCOPE = 244, - -- Tools - FIND = 301, - FIND_NEXT = 302, - FIND_PREV = 303, - FIND_AND_REPLACE = 304, - REPLACE = 305, - REPLACE_ALL = 306, - FIND_IN_FILES = 308, - FIND_INCREMENTAL = 311, - GOTO_NEXT_FILE_FOUND = 309, - GOTO_PREV_FILE_FOUND = 310, - GOTO_LINE = 307, - FOCUS_COMMAND_ENTRY = 401, - RUN = 420, - COMPILE = 421, - INSERT_SNIPPET = 402, - PREVIOUS_SNIPPET_PLACEHOLDER = 403, - CANCEL_SNIPPET = 404, - LIST_SNIPPETS = 405, - SHOW_SCOPE = 406, - ADD_MULTIPLE_LINE = 407, - ADD_MULTIPLE_LINES = 408, - REMOVE_MULTIPLE_LINE = 409, - REMOVE_MULTIPLE_LINES = 410, - UPDATE_MULTIPLE_LINES = 411, - FINISH_MULTIPLE_LINES = 412, - TOGGLE_BOOKMARK = 416, - CLEAR_BOOKMARKS = 417, - GOTO_NEXT_BOOKMARK = 418, - GOTO_PREV_BOOKMARK = 419, - -- Buffer - NEXT_BUFFER = 501, - PREV_BUFFER = 502, - TOGGLE_VIEW_EOL = 503, - TOGGLE_WRAP_MODE = 504, - TOGGLE_SHOW_INDENT_GUIDES = 505, - TOGGLE_USE_TABS = 506, - TOGGLE_VIEW_WHITESPACE = 507, - EOL_MODE_CRLF = 509, - EOL_MODE_CR = 510, - EOL_MODE_LF = 511, - ENCODING_UTF8 = 512, - ENCODING_ASCII = 513, - ENCODING_ISO88591 = 514, - ENCODING_MACROMAN = 515, - ENCODING_UTF16 = 516, - REFRESH_SYNTAX_HIGHLIGHTING = 508, - SWITCH_BUFFER = 517, - -- View - NEXT_VIEW = 601, - PREV_VIEW = 602, - SPLIT_VIEW_VERTICAL = 603, - SPLIT_VIEW_HORIZONTAL = 604, - UNSPLIT_VIEW = 605, - UNSPLIT_ALL_VIEWS = 606, - GROW_VIEW = 607, - SHRINK_VIEW = 608, - -- Lexers (will be generated dynamically) - LEXER_START = 801, - -- Help - MANUAL = 901, - LUADOC = 902, - ABOUT = 903, -} - - -local menubar = { - gtkmenu { - title = l.MENU_FILE_TITLE, - { l.MENU_FILE_NEW, ID.NEW }, - { l.MENU_FILE_OPEN, ID.OPEN }, - { l.MENU_FILE_RELOAD, ID.RELOAD }, - { l.MENU_FILE_SAVE, ID.SAVE }, - { l.MENU_FILE_SAVEAS, ID.SAVEAS }, - { SEPARATOR, ID.SEPARATOR }, - { l.MENU_FILE_CLOSE, ID.CLOSE }, - { l.MENU_FILE_CLOSE_ALL, ID.CLOSE_ALL }, - { SEPARATOR, ID.SEPARATOR }, - { l.MENU_FILE_LOAD_SESSION, ID.LOAD_SESSION }, - { l.MENU_FILE_SAVE_SESSION, ID.SAVE_SESSION }, - { SEPARATOR, ID.SEPARATOR }, - { l.MENU_FILE_QUIT, ID.QUIT }, - }, - gtkmenu { - title = l.MENU_EDIT_TITLE, - { l.MENU_EDIT_UNDO, ID.UNDO }, - { l.MENU_EDIT_REDO, ID.REDO }, - { SEPARATOR, ID.SEPARATOR }, - { l.MENU_EDIT_CUT, ID.CUT }, - { l.MENU_EDIT_COPY, ID.COPY }, - { l.MENU_EDIT_PASTE, ID.PASTE }, - { l.MENU_EDIT_DELETE, ID.DELETE }, - { l.MENU_EDIT_SELECT_ALL, ID.SELECT_ALL }, - { SEPARATOR, ID.SEPARATOR }, - { l.MENU_EDIT_MATCH_BRACE, ID.MATCH_BRACE }, - { l.MENU_EDIT_SELECT_TO_BRACE, ID.SELECT_TO_BRACE }, - { l.MENU_EDIT_COMPLETE_WORD, ID.COMPLETE_WORD }, - { l.MENU_EDIT_DELETE_WORD, ID.DELETE_WORD }, - { l.MENU_EDIT_TRANSPOSE_CHARACTERS, ID.TRANSPOSE_CHARACTERS }, - { l.MENU_EDIT_SQUEEZE, ID.SQUEEZE }, - { l.MENU_EDIT_JOIN_LINES, ID.JOIN_LINES }, - { l.MENU_EDIT_CONVERT_INDENTATION, ID.CONVERT_INDENTATION }, - { title = l.MENU_EDIT_SEL_TITLE, - { title = l.MENU_EDIT_SEL_ENC_TITLE, - { l.MENU_EDIT_SEL_ENC_HTML_TAGS, ID.ENCLOSE_IN_HTML_TAGS }, - { l.MENU_EDIT_SEL_ENC_HTML_SINGLE_TAG, ID.ENCLOSE_IN_HTML_SINGLE_TAG }, - { l.MENU_EDIT_SEL_ENC_DOUBLE_QUOTES, ID.ENCLOSE_IN_DOUBLE_QUOTES }, - { l.MENU_EDIT_SEL_ENC_SINGLE_QUOTES, ID.ENCLOSE_IN_SINGLE_QUOTES }, - { l.MENU_EDIT_SEL_ENC_PARENTHESES, ID.ENCLOSE_IN_PARENTHESES }, - { l.MENU_EDIT_SEL_ENC_BRACKETS, ID.ENCLOSE_IN_BRACKETS }, - { l.MENU_EDIT_SEL_ENC_BRACES, ID.ENCLOSE_IN_BRACES }, - { l.MENU_EDIT_SEL_ENC_CHAR_SEQ, ID.ENCLOSE_IN_CHARACTER_SEQUENCE }, - }, - { l.MENU_EDIT_SEL_GROW, ID.GROW_SELECTION }, - }, - { title = l.MENU_EDIT_SEL_IN_TITLE, - { l.MENU_EDIT_SEL_IN_HTML_TAG, ID.SELECT_IN_HTML_TAG }, - { l.MENU_EDIT_SEL_IN_DOUBLE_QUOTE, ID.SELECT_IN_DOUBLE_QUOTE }, - { l.MENU_EDIT_SEL_IN_SINGLE_QUOTE, ID.SELECT_IN_SINGLE_QUOTE }, - { l.MENU_EDIT_SEL_IN_PARENTHESIS, ID.SELECT_IN_PARENTHESIS }, - { l.MENU_EDIT_SEL_IN_BRACKET, ID.SELECT_IN_BRACKET }, - { l.MENU_EDIT_SEL_IN_BRACE, ID.SELECT_IN_BRACE }, - { l.MENU_EDIT_SEL_IN_WORD, ID.SELECT_IN_WORD }, - { l.MENU_EDIT_SEL_IN_LINE, ID.SELECT_IN_LINE }, - { l.MENU_EDIT_SEL_IN_PARAGRAPH, ID.SELECT_IN_PARAGRAPH }, - { l.MENU_EDIT_SEL_IN_INDENTED_BLOCK, ID.SELECT_IN_INDENTED_BLOCK }, - { l.MENU_EDIT_SEL_IN_SCOPE, ID.SELECT_IN_SCOPE }, - }, - }, - gtkmenu { - title = l.MENU_TOOLS_TITLE, - { title = l.MENU_TOOLS_SEARCH_TITLE, - { l.MENU_TOOLS_SEARCH_FIND, ID.FIND }, - { l.MENU_TOOLS_SEARCH_FIND_NEXT, ID.FIND_NEXT }, - { l.MENU_TOOLS_SEARCH_FIND_PREV, ID.FIND_PREV }, - { l.MENU_TOOLS_SEARCH_FIND_AND_REPLACE, ID.FIND_AND_REPLACE }, - { l.MENU_TOOLS_SEARCH_REPLACE, ID.REPLACE }, - { l.MENU_TOOLS_SEARCH_REPLACE_ALL, ID.REPLACE_ALL }, - { l.MENU_TOOLS_SEARCH_FIND_INCREMENTAL, ID.FIND_INCREMENTAL }, - { SEPARATOR, ID.SEPARATOR }, - { l.MENU_TOOLS_SEARCH_FIND_IN_FILES, ID.FIND_IN_FILES }, - { l.MENU_TOOLS_SEARCH_GOTO_NEXT_FILE_FOUND, ID.GOTO_NEXT_FILE_FOUND }, - { l.MENU_TOOLS_SEARCH_GOTO_PREV_FILE_FOUND, ID.GOTO_PREV_FILE_FOUND }, - { SEPARATOR, ID.SEPARATOR }, - { l.MENU_TOOLS_SEARCH_GOTO_LINE, ID.GOTO_LINE }, - }, - { l.MENU_TOOLS_FOCUS_COMMAND_ENTRY, ID.FOCUS_COMMAND_ENTRY }, - { SEPARATOR, ID.SEPARATOR }, - { l.MENU_TOOLS_RUN, ID.RUN }, - { l.MENU_TOOLS_COMPILE, ID.COMPILE }, - { SEPARATOR, ID.SEPARATOR }, - { title = l.MENU_TOOLS_SNIPPETS_TITLE, - { l.MENU_TOOLS_SNIPPETS_INSERT, ID.INSERT_SNIPPET }, - { l.MENU_TOOLS_SNIPPETS_PREV_PLACE, ID.PREVIOUS_SNIPPET_PLACEHOLDER }, - { l.MENU_TOOLS_SNIPPETS_CANCEL, ID.CANCEL_SNIPPET }, - { l.MENU_TOOLS_SNIPPETS_LIST, ID.LIST_SNIPPETS }, - { l.MENU_TOOLS_SNIPPETS_SHOW_SCOPE, ID.SHOW_SCOPE }, - }, - { title = l.MENU_TOOLS_BM_TITLE, - { l.MENU_TOOLS_BM_TOGGLE, ID.TOGGLE_BOOKMARK }, - { l.MENU_TOOLS_BM_CLEAR_ALL, ID.CLEAR_BOOKMARKS }, - { l.MENU_TOOLS_BM_NEXT, ID.GOTO_NEXT_BOOKMARK }, - { l.MENU_TOOLS_BM_PREV, ID.GOTO_PREV_BOOKMARK }, - }, - }, - gtkmenu { - title = l.MENU_BUF_TITLE, - { l.MENU_BUF_NEXT, ID.NEXT_BUFFER }, - { l.MENU_BUF_PREV, ID.PREV_BUFFER }, - { l.MENU_BUF_SWITCH, ID.SWITCH_BUFFER }, - { SEPARATOR, ID.SEPARATOR }, - { l.MENU_BUF_TOGGLE_VIEW_EOL, ID.TOGGLE_VIEW_EOL }, - { l.MENU_BUF_TOGGLE_WRAP, ID.TOGGLE_WRAP_MODE }, - { l.MENU_BUF_TOGGLE_INDENT_GUIDES, ID.TOGGLE_SHOW_INDENT_GUIDES }, - { l.MENU_BUF_TOGGLE_TABS, ID.TOGGLE_USE_TABS }, - { l.MENU_BUF_TOGGLE_VIEW_WHITESPACE, ID.TOGGLE_VIEW_WHITESPACE }, - { SEPARATOR, ID.SEPARATOR }, - { title = l.MENU_BUF_EOL_MODE_TITLE, - { l.MENU_BUF_EOL_MODE_CRLF, ID.EOL_MODE_CRLF }, - { l.MENU_BUF_EOL_MODE_CR, ID.EOL_MODE_CR }, - { l.MENU_BUF_EOL_MODE_LF, ID.EOL_MODE_LF }, - }, - { title = l.MENU_BUF_ENCODING_TITLE, - { l.MENU_BUF_ENCODING_UTF8, ID.ENCODING_UTF8 }, - { l.MENU_BUF_ENCODING_ASCII, ID.ENCODING_ASCII }, - { l.MENU_BUF_ENCODING_ISO88591, ID.ENCODING_ISO88591 }, - { l.MENU_BUF_ENCODING_MACROMAN, ID.ENCODING_MACROMAN }, - { l.MENU_BUF_ENCODING_UTF16, ID.ENCODING_UTF16 }, - }, - { SEPARATOR, ID.SEPARATOR }, - { l.MENU_BUF_REFRESH, ID.REFRESH_SYNTAX_HIGHLIGHTING }, - }, - gtkmenu { - title = l.MENU_VIEW_TITLE, - { l.MENU_VIEW_NEXT, ID.NEXT_VIEW }, - { l.MENU_VIEW_PREV, ID.PREV_VIEW }, - { SEPARATOR, ID.SEPARATOR }, - { l.MENU_VIEW_SPLIT_VERTICAL, ID.SPLIT_VIEW_VERTICAL }, - { l.MENU_VIEW_SPLIT_HORIZONTAL, ID.SPLIT_VIEW_HORIZONTAL }, - { l.MENU_VIEW_UNSPLIT, ID.UNSPLIT_VIEW }, - { l.MENU_VIEW_UNSPLIT_ALL, ID.UNSPLIT_ALL_VIEWS }, - { SEPARATOR, ID.SEPARATOR }, - { l.MENU_VIEW_GROW, ID.GROW_VIEW }, - { l.MENU_VIEW_SHRINK, ID.SHRINK_VIEW }, - }, - -- Lexer menu inserted here - gtkmenu { - title = l.MENU_HELP_TITLE, - { l.MENU_HELP_MANUAL, ID.MANUAL }, - { l.MENU_HELP_LUADOC, ID.LUADOC }, - { SEPARATOR, ID.SEPARATOR }, - { l.MENU_HELP_ABOUT, ID.ABOUT }, - }, -} -local lexer_menu = { title = l.MENU_LEX_TITLE } -for _, lexer in ipairs(_m.textadept.mime_types.lexers) do - lexer_menu[#lexer_menu + 1] = { lexer, ID.LEXER_START + #lexer_menu } -end -table.insert(menubar, #menubar, gtkmenu(lexer_menu)) -- before 'Help' -gui.menubar = menubar - -local b, v = 'buffer', 'view' -local m_snippets = _m.textadept.snippets -local m_editing = _m.textadept.editing -local m_bookmarks = _m.textadept.bookmarks -local m_run = _m.textadept.run - -local function set_encoding(encoding) - buffer:set_encoding(encoding) - events.emit('update_ui') -- for updating statusbar -end -local function toggle_setting(setting) - local state = buffer[setting] - if type(state) == 'boolean' then - buffer[setting] = not state - elseif type(state) == 'number' then - buffer[setting] = buffer[setting] == 0 and 1 or 0 - end - events.emit('update_ui') -- for updating statusbar -end -local function set_eol_mode(mode) - buffer.eol_mode = mode - buffer:convert_eo_ls(mode) - events.emit('update_ui') -- for updating statusbar -end -local function set_lexer(lexer) - buffer:set_lexer(lexer) - buffer:colourise(0, -1) - events.emit('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.MENU_BROWSER_ERROR..url) end - else - cmd = string.format(MAC and 'open "file://%s"' or 'xdg-open "%s" &', url) - if os.execute(cmd) ~= 0 then error(l.MENU_BROWSER_ERROR..url) end - end -end - -local actions = { - -- File - [ID.NEW] = { new_buffer }, - [ID.OPEN] = { io.open_file }, - [ID.RELOAD] = { 'reload', b }, - [ID.SAVE] = { 'save', b }, - [ID.SAVEAS] = { 'save_as', b }, - [ID.CLOSE] = { 'close', b }, - [ID.CLOSE_ALL] = { io.close_all }, - [ID.LOAD_SESSION] = { - function() - local utf8_filename = - gui.dialog('fileselect', - '--title', l.MENU_LOAD_SESSION_TITLE, - '--with-directory', - (_SESSIONFILE or ''):match('.+[/\\]') or '', - '--with-file', - (_SESSIONFILE or ''):match('[^/\\]+$') or '', - '--no-newline') - if #utf8_filename > 0 then - _m.textadept.session.load(utf8_filename:iconv(_CHARSET, 'UTF-8')) - end - end - }, - [ID.SAVE_SESSION] = { - function() - local utf8_filename = - gui.dialog('filesave', - '--title', l.MENU_SAVE_SESSION_TITLE, - '--with-directory', - (_SESSIONFILE or ''):match('.+[/\\]') or '', - '--with-file', - (_SESSIONFILE or ''):match('[^/\\]+$') or '', - '--no-newline') - if #utf8_filename > 0 then - _m.textadept.session.save(utf8_filename:iconv(_CHARSET, 'UTF-8')) - end - end - }, - [ID.QUIT] = { quit }, - -- Edit - [ID.UNDO] = { 'undo', b }, - [ID.REDO] = { 'redo', b }, - [ID.CUT] = { 'cut', b }, - [ID.COPY] = { 'copy', b }, - [ID.PASTE] = { 'paste', b }, - [ID.DELETE] = { 'clear', b }, - [ID.SELECT_ALL] = { 'select_all', b }, - [ID.MATCH_BRACE] = { m_editing.match_brace }, - [ID.SELECT_TO_BRACE] = { m_editing.match_brace, 'select' }, - [ID.COMPLETE_WORD] = { m_editing.autocomplete_word, '%w_' }, - [ID.DELETE_WORD] = { m_editing.current_word, 'delete' }, - [ID.TRANSPOSE_CHARACTERS] = { m_editing.transpose_chars }, - [ID.SQUEEZE] = { m_editing.squeeze }, - [ID.JOIN_LINES] = { m_editing.join_lines }, - [ID.CONVERT_INDENTATION] = { m_editing.convert_indentation }, - -- Edit -> Selection -> Enclose in... - [ID.ENCLOSE_IN_HTML_TAGS] = { m_editing.enclose, 'tag' }, - [ID.ENCLOSE_IN_HTML_SINGLE_TAG] = { m_editing.enclose, 'single_tag' }, - [ID.ENCLOSE_IN_DOUBLE_QUOTES] = { m_editing.enclose, 'dbl_quotes' }, - [ID.ENCLOSE_IN_SINGLE_QUOTES] = { m_editing.enclose, 'sng_quotes' }, - [ID.ENCLOSE_IN_PARENTHESES] = { m_editing.enclose, 'parens' }, - [ID.ENCLOSE_IN_BRACKETS] = { m_editing.enclose, 'brackets' }, - [ID.ENCLOSE_IN_BRACES] = { m_editing.enclose, 'braces' }, - [ID.ENCLOSE_IN_CHARACTER_SEQUENCE] = { m_editing.enclose, 'chars' }, - -- Edit -> Selection - [ID.GROW_SELECTION] = { m_editing.grow_selection, 1 }, - -- Edit -> Select In... - [ID.SELECT_IN_HTML_TAG] = { m_editing.select_enclosed, 'tags' }, - [ID.SELECT_IN_DOUBLE_QUOTE] = { m_editing.select_enclosed, 'dbl_quotes' }, - [ID.SELECT_IN_SINGLE_QUOTE] = { m_editing.select_enclosed, 'sng_quotes' }, - [ID.SELECT_IN_PARENTHESIS] = { m_editing.select_enclosed, 'parens' }, - [ID.SELECT_IN_BRACKET] = { m_editing.select_enclosed, 'brackets' }, - [ID.SELECT_IN_BRACE] = { m_editing.select_enclosed, 'braces' }, - [ID.SELECT_IN_WORD] = { m_editing.current_word, 'select' }, - [ID.SELECT_IN_LINE] = { m_editing.select_line }, - [ID.SELECT_IN_PARAGRAPH] = { m_editing.select_paragraph }, - [ID.SELECT_IN_INDENTED_BLOCK] = { m_editing.select_indented_block }, - [ID.SELECT_IN_SCOPE] = { m_editing.select_scope }, - -- Tools - [ID.FIND] = { gui.find.focus }, - [ID.FIND_NEXT] = { gui.find.call_find_next }, - [ID.FIND_PREV] = { gui.find.call_find_prev }, - [ID.FIND_AND_REPLACE] = { gui.find.focus }, - [ID.REPLACE] = { gui.find.call_replace }, - [ID.REPLACE_ALL] = { gui.find.call_replace_all }, - [ID.FIND_INCREMENTAL] = { gui.find.find_incremental }, - [ID.FIND_IN_FILES] = { - function() - gui.find.in_files = true - gui.find.focus() - end - }, - [ID.GOTO_NEXT_FILE_FOUND] = { gui.find.goto_file_in_list, true }, - [ID.GOTO_PREV_FILE_FOUND] = { gui.find.goto_file_in_list, false }, - [ID.GOTO_LINE] = { m_editing.goto_line }, - [ID.FOCUS_COMMAND_ENTRY] = { gui.command_entry.focus }, - [ID.RUN] = { m_run.run }, - [ID.COMPILE] = { m_run.compile }, - -- Tools -> Snippets - [ID.INSERT_SNIPPET] = { m_snippets.insert }, - [ID.PREVIOUS_SNIPPET_PLACEHOLDER] = { m_snippets.prev }, - [ID.CANCEL_SNIPPET] = { m_snippets.cancel_current }, - [ID.LIST_SNIPPETS] = { m_snippets.list }, - [ID.SHOW_SCOPE] = { m_snippets.show_style }, - -- Tools -> Bookmark - [ID.TOGGLE_BOOKMARK] = { m_bookmarks.toggle }, - [ID.CLEAR_BOOKMARKS] = { m_bookmarks.clear }, - [ID.GOTO_NEXT_BOOKMARK] = { m_bookmarks.goto_next }, - [ID.GOTO_PREV_BOOKMARK] = { m_bookmarks.goto_prev }, - -- Buffer - [ID.NEXT_BUFFER] = { 'goto_buffer', v, 1, false }, - [ID.PREV_BUFFER] = { 'goto_buffer', v, -1, false }, - [ID.TOGGLE_VIEW_EOL] = { toggle_setting, 'view_eol' }, - [ID.TOGGLE_WRAP_MODE] = { toggle_setting, 'wrap_mode' }, - [ID.TOGGLE_SHOW_INDENT_GUIDES] = { toggle_setting, 'indentation_guides' }, - [ID.TOGGLE_USE_TABS] = { toggle_setting, 'use_tabs' }, - [ID.TOGGLE_VIEW_WHITESPACE] = { toggle_setting, 'view_ws' }, - [ID.EOL_MODE_CRLF] = { set_eol_mode, 0 }, - [ID.EOL_MODE_CR] = { set_eol_mode, 1 }, - [ID.EOL_MODE_LF] = { set_eol_mode, 2 }, - [ID.ENCODING_UTF8] = { set_encoding, 'UTF-8' }, - [ID.ENCODING_ASCII] = { set_encoding, 'ASCII' }, - [ID.ENCODING_ISO88591] = { set_encoding, 'ISO-8859-1' }, - [ID.ENCODING_MACROMAN] = { set_encoding, 'MacRoman' }, - [ID.ENCODING_UTF16] = { set_encoding, 'UTF-16LE' }, - [ID.REFRESH_SYNTAX_HIGHLIGHTING] = { 'colourise', b, 0, -1 }, - [ID.SWITCH_BUFFER] = { gui.switch_buffer }, - -- View - [ID.NEXT_VIEW] = { gui.goto_view, 1, false }, - [ID.PREV_VIEW] = { gui.goto_view, -1, false }, - [ID.SPLIT_VIEW_VERTICAL] = { 'split', v }, - [ID.SPLIT_VIEW_HORIZONTAL] = { 'split', v, false }, - [ID.UNSPLIT_VIEW] = { function() view:unsplit() end }, - [ID.UNSPLIT_ALL_VIEWS] = { function() while view:unsplit() do end end }, - [ID.GROW_VIEW] = { - function() if view.size then view.size = view.size + 10 end end - }, - [ID.SHRINK_VIEW] = { - function() if view.size then view.size = view.size - 10 end end - }, - -- Help - [ID.MANUAL] = { open_webpage, _HOME..'/doc/manual/1_Introduction.html' }, - [ID.LUADOC] = { open_webpage, _HOME..'/doc/index.html' }, - [ID.ABOUT] = { - gui.dialog, 'ok-msgbox', '--title', 'Textadept', '--informative-text', - _RELEASE, '--no-cancel' - }, -} - --- Most of this handling code comes from keys.lua. -events.connect('menu_clicked', - function(menu_id) - local active_table = actions[menu_id] - if menu_id >= ID.LEXER_START and menu_id < ID.LEXER_START + 99 then - active_table = - { set_lexer, lexer_menu[menu_id - ID.LEXER_START + 1][1] } - end - local f, args - if active_table and #active_table > 0 then - local func = active_table[1] - if type(func) == 'function' then - f, args = func, { unpack(active_table, 2) } - elseif type(func) == 'string' then - local object = active_table[2] - if object == 'buffer' then - f, args = buffer[func], { buffer, unpack(active_table, 3) } - elseif object == 'view' then - f, args = view[func], { view, unpack(active_table, 3) } - end - end - if f and args then - local ret, retval = pcall(f, unpack(args)) - if not ret then error(retval) end - else - error(l.MENU_UNKNOWN_COMMAND..tostring(func)) - end - end - end) - --- Right-click context menu. -gui.context_menu = gtkmenu { - { l.MENU_EDIT_UNDO, ID.UNDO }, - { l.MENU_EDIT_REDO, ID.REDO }, - { SEPARATOR, ID.SEPARATOR }, - { l.MENU_EDIT_CUT, ID.CUT }, - { l.MENU_EDIT_COPY, ID.COPY }, - { l.MENU_EDIT_PASTE, ID.PASTE }, - { l.MENU_EDIT_DELETE, ID.DELETE }, - { SEPARATOR, ID.SEPARATOR }, - { l.MENU_EDIT_SELECT_ALL, ID.SELECT_ALL } -} |