diff options
-rw-r--r-- | core/._m.lua | 6 | ||||
-rw-r--r-- | core/.browser.lua | 68 | ||||
-rw-r--r-- | core/.pm.lua | 105 | ||||
-rw-r--r-- | core/events.lua | 26 | ||||
-rw-r--r-- | core/ext/key_commands.lua | 38 | ||||
-rw-r--r-- | core/ext/pm.lua | 60 | ||||
-rw-r--r-- | core/ext/pm/buffer_browser.lua | 91 | ||||
-rw-r--r-- | core/ext/pm/ctags_browser.lua | 253 | ||||
-rw-r--r-- | core/ext/pm/file_browser.lua | 111 | ||||
-rw-r--r-- | core/ext/pm/modules_browser.lua | 210 | ||||
-rw-r--r-- | core/locale.conf | 112 | ||||
-rw-r--r-- | init.lua | 13 | ||||
-rw-r--r-- | modules/textadept/session.lua | 83 | ||||
-rw-r--r-- | src/lua_interface.c | 209 | ||||
-rw-r--r-- | src/textadept.c | 231 | ||||
-rw-r--r-- | src/textadept.h | 8 |
16 files changed, 42 insertions, 1582 deletions
diff --git a/core/._m.lua b/core/._m.lua index 611e0647..e50885a6 100644 --- a/core/._m.lua +++ b/core/._m.lua @@ -48,12 +48,6 @@ module('_m') -- Language-specific modules are automatically loaded when a file of that -- language is loaded or a buffer's lexer is set to that language. -- --- ## Managing Modules --- --- Modules are easy to create and edit in the filesystem, but you can use the --- `modules` PM browser to create Language-specific modules from a generic --- template, or manage all available modules. --- -- ## Modules and Key Commands -- -- When assigning [key commands][key_commands] to module functions, do not diff --git a/core/.browser.lua b/core/.browser.lua deleted file mode 100644 index a9db7ada..00000000 --- a/core/.browser.lua +++ /dev/null @@ -1,68 +0,0 @@ --- Copyright 2007-2010 Mitchell mitchell<att>caladbolg.net. See LICENSE. --- This is a DUMMY FILE used for making LuaDoc for a textadept.pm browser. - ---- --- A model browser for the Textadept project manager. -module('textadept.pm.browser') - ---- --- Determines whether or not to use this browser for the text in the project --- manager entry. --- All loaded browsers are called in sequence to match to the given entry text. --- When a match is found, that browser is used. --- @param entry_text The text in the entry. --- @return boolean indicating whether or not to use this browser. -function matches(entry_text) - ---- --- Requests treeview contents from browser that matches pm_entry's text. --- This function is called internally and shouldn't be called by a script. --- @param full_path A numerically indexed table of treeview item parents. The --- first index contains the text of pm_entry. Subsequent indexes contain the --- ID's of parents of the child requested for expanding (if any). --- @param expanding Optional flag indicating if the contents of a parent are --- being requested. Defaults to false. --- @return table of tables to for display in the treeview (single level). --- Each key in the return table is the treeview item's ID. The table value --- has the following recognized fields: --- parent - boolean value indicating if this entry can contain children. If --- true, an expanding arrow is displayed next to the entry. --- pixbuf - a string representing a GTK stock-id whose icon is displayed --- next to an entry. --- text - the entry's Pango marked-up display text. --- Note that only a SINGLE level of data needs to be returned. When parents --- are expanded, this function is called again to get that level of data. -function get_contents_for(full_path, expanding) - ---- --- Performs an action based on the selected treeview item. --- This function is called internally and shouldn't be called by a script. --- @param selected_item Identical to 'full_path' in get_contents_for. --- @see get_contents_for -function perform_action(selected_item) - ---- --- Creates a context menu based on the selected treeview item. --- This function is called internally and shouldn't be called by a script. --- @param selected_item Identical to 'full_path' in pm.get_contents_for. --- @return table of menu items. --- The return table consists of an ordered list of strings to be used to --- construct a context menu. The strings are handled as follows: --- 'gtk-*' - a stock menu item is created based on the GTK stock-id. --- 'separator' - a menu separator item is created. --- Otherwise a regular menu item with a mnemonic is created. -function get_context_menu(selected_item) - ---- --- Performs an action based on the selected menu item. --- This function is called internally and shouldn't be called by a script. --- @param menu_id The numeric ID of the menu item. --- @param selected_item Identical to 'full_path' in get_contents_for. --- @see get_contents_for -function perform_menu_action(menu_id, selected_item) - ---- --- Toggles the width of the project manager. --- If the pm is visible, it's width is saved and then set to 0, effectively --- hiding it. If it is hidden, the width is restored. -function toggle_visible() diff --git a/core/.pm.lua b/core/.pm.lua deleted file mode 100644 index 4bca6730..00000000 --- a/core/.pm.lua +++ /dev/null @@ -1,105 +0,0 @@ --- Copyright 2007-2010 Mitchell mitchell<att>caladbolg.net. See LICENSE. --- This is a DUMMY FILE used for making LuaDoc for built-in functions in the --- global textadept.pm table. - ---- --- Textadept's project manager. -module('textadept.pm') - --- Markdown: --- ## Fields --- --- * `entry_text`: The text in the entry. --- * `width`: The width of the project manager. --- * `cursor`: The cursor in the project manager (string representation of --- current `GtkTreePath`). --- --- ## Overview --- --- The PM uses different [browsers][browsers] to display heirarchical data. --- --- [browsers]: ../modules/textadept.pm.browser.html --- --- ## Interactive Search --- --- Typing text into the project manager view begins the interactive search. --- If the text matches ANY part of an item in the view (case sensitively), the --- item is highlighted and subsequent matches can be navigated to using the --- up/down arrow keys. --- --- ## Customizing Look and Feel --- --- There is no way to theme the dialog from within Textadept. Instead you can --- use [GTK Resource files][gtkrc]. The pm entry and view have widget names of --- `textadept-pm-entry` and `textadept-pm-view` respectively. --- --- [gtkrc]: http://library.gnome.org/devel/gtk/unstable/gtk-Resource-Files.html. --- --- My RC file looks something like this: --- --- pixmap_path "/usr/share/icons/Tango/:/home/mitchell/.icons/prog/" --- style "textadept-pm-display-style" { --- fg[NORMAL] = "#AAAAAA" # treeview arrows foreground --- fg[PRELIGHT] = "#AAAAAA" # treeview arrows hover foreground --- bg[NORMAL] = "#333333" # entry border background --- base[NORMAL] = "#333333" # entry, treeview background --- base[ACTIVE] = "#444444" # treeview unfocused selection background --- base[SELECTED] = "#444444" # entry, treeview selection background --- text[NORMAL] = "#AAAAAA" # entry, treeview text foreground --- text[ACTIVE] = "#AAAAAA" # treeview unfocused selection text --- text[SELECTED] = "#DDDDDD" # entry, treeview selection text foreground --- stock["gtk-directory"] = {{ "16x16/places/stock_folder.png", LTR }} --- stock["gtk-folder-new"] = {{ "16x16/actions/folder_new.png", LTR }} --- stock["prog-class"] = {{ "class.png", LTR }} --- stock["prog-enum"] = {{ "enum.png", LTR }} --- stock["prog-field"] = {{ "field.png", LTR }} --- stock["prog-interface"] = {{ "interface.png", LTR }} --- stock["prog-literal"] = {{ "literal.png", LTR }} --- stock["prog-method"] = {{ "method.png", LTR }} --- stock["prog-namespace"] = {{ "namespace.png", LTR }} --- stock["prog-reference"] = {{ "reference.png", LTR }} --- stock["prog-struct"] = {{ "struct.png", LTR }} --- } --- widget "*textadept-pm-entry" style "textadept-pm-display-style" --- widget "*textadept-pm-view" style "textadept-pm-display-style" - ---- Requests the project manager to get its contents based on its entry text. -function activate() end - ---- --- Adds a browser prefix to the list of browsers available in the project --- manager entry combo box. --- @param prefix The text to add. -function add_browser(prefix) end - ---- Clears the project manager contents. -function clear() end - ---- --- Adds contents to the Project Manager view. --- @param contents Table of tables to for display in the treeview (single --- level). Each key in the return table is the treeview item's ID. The table --- value has the following recognized fields: --- * parent - boolean value indicating if this entry can contain children. --- If true, an expanding arrow is displayed next to the entry. --- * pixbuf - a string representing a GTK stock-id whose icon is displayed --- next to an entry. --- * text - the entry's Pango marked-up display text. --- Note that only a SINGLE level of data needs to be returned. When parents --- are expanded, this function is called again to get that level of data. --- @param parent String representation of parent GtkTreePath to add the child --- contents to. -function fill(contents, parent) - ---- Focuses the project manager entry. -function focus() end - ---- --- Shows a context menu. --- @param menu Table of menu items. It consists of an ordered list of strings --- to be used to construct a context menu. The strings are handled as follows: --- * 'gtk-*' - a stock menu item is created based on the GTK stock-id. --- * 'separator' - a menu separator item is created. --- * Otherwise a regular menu item with a mnemonic is created. --- @param event The GDK event associated with the context menu request. -function show_context_menu(menu, event) end diff --git a/core/events.lua b/core/events.lua index bcd468eb..9ea46bbe 100644 --- a/core/events.lua +++ b/core/events.lua @@ -115,30 +115,6 @@ module('textadept.events', package.seeall) -- Called when a menu item is selected. -- - menu\_id: the numeric ID of the menu item set in -- [`textadept.gtkmenu()`][textadept_gtkmenu]. --- * **pm\_contents\_request** (full\_path, expanding)<br /> --- Called when the [PM][PM] requests data to display. --- - full\_path: a numerically indexed table of treeview item parents. The --- first index contains the text of the PM entry. Subsequent indices --- contain the ID's of parents of the child (if any). --- - expanding: indicates if the contents of a parent are being requested. --- * **pm\_item\_selected** (selected\_item)<br /> --- Called when an item in the [PM][PM] is double-clicked or activated. --- - selected\_item: identical to `full_path` in the `pm_contents_request` --- event. --- * **pm\_context\_menu\_request** (selected\_item, gdkevent)<br /> --- Called when the context menu for an item in the [PM][PM] is requested. --- - selected\_item: identical to `full_path` in the `pm_contents_request` --- event. --- - gdkevent: the GDK event associated with the request. It must be --- passed to [`textadept.pm.show_context_menu()`][pm_show_menu]. --- * **pm\_menu\_clicked** (menu\_id, selected\_item)<br /> --- Called when a [PM][PM] context menu item is selected. --- - menu\_id: the numeric ID of the context menu item set in --- [`textadept.gtkmenu()`][textadept_gtkmenu]. --- - selected\_item: identical to `full_path` in the `pm_contents_request` --- event. --- * **pm\_view\_filled** ()<br /> --- Called when the [PM][PM] view is filled with data. -- * **find** (text, next)<br /> -- Called when attempting to finding text via the Find dialog box. -- - text: the text to search for. @@ -158,8 +134,6 @@ module('textadept.events', package.seeall) -- [view]: ../modules/view.html -- [textadept_reset]: ../modules/textadept.html#reset -- [textadept_gtkmenu]: ../modules/textadept.html#gtkmenu --- [PM]: ../modules/textadept.pm.html --- [pm_show_menu]: ../modules/textadept.pm.html#show_context_menu -- -- ## Example -- diff --git a/core/ext/key_commands.lua b/core/ext/key_commands.lua index 738199e6..6181d378 100644 --- a/core/ext/key_commands.lua +++ b/core/ext/key_commands.lua @@ -246,25 +246,6 @@ if not MAC then -- TODO: { function() view.size = view.size - 10 end } } - -- Project Manager - local function pm_activate(text) - t.pm.entry_text = text - t.pm.activate() - end - keys.cP = { function() if t.pm.width > 0 then t.pm.toggle_visible() end end } - keys.cp = { - function() - if t.pm.width == 0 then t.pm.toggle_visible() end - t.pm.focus() - end - } - keys.cap = { - c = { pm_activate, 'ctags' }, - b = { pm_activate, 'buffers' }, - f = { pm_activate, '/' }, - m = { pm_activate, 'modules' }, - } - -- Miscellaneous not in standard menu. -- Recent files. local RECENT_FILES = 1 @@ -426,25 +407,6 @@ else -- TODO: { function() view.size = view.size - 10 end } } - -- Project Manager - local function pm_activate(text) - t.pm.entry_text = text - t.pm.activate() - end - keys.aP = { function() if t.pm.width > 0 then t.pm.toggle_visible() end end } - keys.ap = { - function() - if t.pm.width == 0 then t.pm.toggle_visible() end - t.pm.focus() - end - } - keys.cap = { - c = { pm_activate, 'ctags' }, - b = { pm_activate, 'buffers' }, - f = { pm_activate, '/' }, - m = { pm_activate, 'modules' }, - } - -- Miscellaneous not in standard menu. -- Recent files. local RECENT_FILES = 1 diff --git a/core/ext/pm.lua b/core/ext/pm.lua deleted file mode 100644 index cec2fd5b..00000000 --- a/core/ext/pm.lua +++ /dev/null @@ -1,60 +0,0 @@ --- Copyright 2007-2010 Mitchell mitchell<att>caladbolg.net. See LICENSE. - -local pm = textadept.pm - -local current_browser = nil - --- For restoring browser cursors -local last_browser_text = nil -local browser_cursors = {} - -textadept.events.add_handler('pm_contents_request', - function(full_path, expanding) - for _, browser in pairs(pm.browsers) do - if browser.matches(full_path[1]) then - current_browser = browser - if last_browser_text and last_browser_text ~= pm.entry_text then - -- Switching browsers, save the current one's cursor. - -- Don't reset last_browser_text here though, we still need to detect - -- the switch when the 'pm_view_filled' event is called so as to restore - -- the cursor to the new browser. - browser_cursors[last_browser_text] = pm.cursor - end - pm.fill(browser.get_contents_for(full_path, expanding), expanding) - textadept.events.handle('pm_view_filled') - end - end - end) - -textadept.events.add_handler('pm_item_selected', - function(selected_item) current_browser.perform_action(selected_item) end) - -textadept.events.add_handler('pm_context_menu_request', - function(selected_item, event) - local menu = current_browser.get_context_menu(selected_item) - if menu then pm.show_context_menu(menu, event) end - end) - -textadept.events.add_handler('pm_menu_clicked', - function(menu_id, selected_item) - current_browser.perform_menu_action(menu_id, selected_item) - end) - --- LuaDoc is in core/.browser.lua. -function pm.toggle_visible() - if pm.width > 0 then - pm.prev_width = pm.width - pm.width = 0 - else - pm.width = pm.prev_width or 150 - end -end - -textadept.events.add_handler('pm_view_filled', - function() -- try to restore previous browser cursor - if last_browser_text ~= pm.entry_text then - last_browser_text = pm.entry_text - local previous_cursor = browser_cursors[pm.entry_text] - if previous_cursor then pm.cursor = previous_cursor end - end - end) diff --git a/core/ext/pm/buffer_browser.lua b/core/ext/pm/buffer_browser.lua deleted file mode 100644 index a97db8ea..00000000 --- a/core/ext/pm/buffer_browser.lua +++ /dev/null @@ -1,91 +0,0 @@ --- Copyright 2007-2010 Mitchell mitchell<att>caladbolg.net. See LICENSE. - -local textadept = _G.textadept -local locale = _G.locale - ---- --- Buffer browser for the Textadept project manager. --- It is enabled with the prefix 'buffers' in the project manager entry field. -module('textadept.pm.browsers.buffer', package.seeall) - -if not RESETTING then textadept.pm.add_browser('buffers') end - -function matches(entry_text) - return entry_text:sub(1, 7) == 'buffers' -end - -function get_contents_for() - local contents = {} - for index, buffer in ipairs(textadept.buffers) do - index = string.format("%02i", index) - contents[index] = { - pixbuf = buffer.dirty and 'gtk-edit' or 'gtk-file', - text = - (buffer.filename or buffer._type or locale.UNTITLED):match('[^/\\]+$') - } - end - return contents -end - -function perform_action(selected_item) - local index = selected_item[2] - local buffer = textadept.buffers[tonumber(index)] - if buffer then - view:goto_buffer(index) - view:focus() - end -end - -local ID = { NEW = 1, OPEN = 2, SAVE = 3, SAVEAS = 4, CLOSE = 5 } - -function get_context_menu(selected_item) - return { - { locale.PM_BROWSER_BUFFER_NEW, ID.NEW }, - { locale.PM_BROWSER_BUFFER_OPEN, ID.OPEN }, - { locale.PM_BROWSER_BUFFER_SAVE, ID.SAVE }, - { locale.PM_BROWSER_BUFFER_SAVEAS, ID.SAVEAS }, - { 'separator', 0 }, - { locale.PM_BROWSER_BUFFER_CLOSE, ID.CLOSE }, - } -end - -function perform_menu_action(menu_id, selected_item) - if menu_id == ID.NEW then - textadept.new_buffer() - elseif menu_id == ID.OPEN then - textadept.io.open() - elseif menu_id == ID.SAVE then - view:goto_buffer(tonumber(selected_item[2])) - buffer:save() - elseif menu_id == ID.SAVEAS then - view:goto_buffer(tonumber(selected_item[2])) - buffer:save_as() - elseif menu_id == ID.CLOSE then - view:goto_buffer(tonumber(selected_item[2])) - buffer:close() - end - textadept.pm.activate() -end - -local function update_view() - if matches(textadept.pm.entry_text) then textadept.pm.activate() end -end -textadept.events.add_handler('file_opened', update_view) -textadept.events.add_handler('buffer_new', update_view) -textadept.events.add_handler('buffer_deleted', update_view) -textadept.events.add_handler('save_point_reached', update_view) -textadept.events.add_handler('save_point_left', update_view) -textadept.events.add_handler('buffer_after_switch', update_view) -textadept.events.add_handler('view_after_switch', update_view) - -local function set_cursor() - if matches(textadept.pm.entry_text) then - for idx, buf in ipairs(textadept.buffers) do - if buf == buffer then - textadept.pm.cursor = idx - 1 - break - end - end - end -end -textadept.events.add_handler('pm_view_filled', set_cursor) diff --git a/core/ext/pm/ctags_browser.lua b/core/ext/pm/ctags_browser.lua deleted file mode 100644 index db2ea27e..00000000 --- a/core/ext/pm/ctags_browser.lua +++ /dev/null @@ -1,253 +0,0 @@ --- Copyright 2007-2010 Mitchell mitchell<att>caladbolg.net. See LICENSE. - -local textadept = _G.textadept -local locale = _G.locale - ---- --- CTags Browser for the Textadept project manager. --- It is enabled with the prefix 'ctags' in the project manager entry field --- followed by either nothing or ':' and the path to a ctags file. If no path --- is specified, the current file is parsed via ctags and its structure shown. -module('textadept.pm.browsers.ctags', package.seeall) - -if not RESETTING then textadept.pm.add_browser('ctags') end - -local FILE_OUT = '/tmp/textadept_output' - ---- --- The current ctags file and current directory. --- When a ctags file is opened, current_dir is set to its dirname. -local current_file, current_dir - ---- --- The table of ctags with property values. --- Each key is the name of a ctags identifier (function, class, etc.) and the --- value is a table containing: --- * The GTK stock-id for the pixbuf to display next to the identifier in the --- tree view (pixbuf key). --- * The display text used for displaying the identifier in the tree view --- (text key). --- * Boolean parent value if the identifier is a container. --- * The line number or pattern used to goto the identifier. --- Note this table is returned by get_contents_for, but only 'pixbuf', --- 'text' and 'parent' fields are read; all others are ignored. --- @class table --- @name tags -local tags - ---- --- Table of associations of tag identifier types for specific languages with --- GTK stock-id pixbufs. --- @class table --- @name pixbuf -local pixbuf = { - lua = { f = 'prog-method' }, - ruby = { - c = 'prog-class', - f = 'prog-method', - F = 'prog-method', - m = 'prog-namespace' - }, - cpp = { - c = 'prog-class', - e = 'prog-enum', - f = 'prog-method', - g = 'prog-enum', - m = 'prog-field', - n = 'prog-namespace', - s = 'prog-struct' - } -} - ---- --- Table of associations of file extensions with languages. --- @class table --- @name language -local language = { - lua = 'lua', - rb = 'ruby', - h = 'cpp', c = 'cpp', cxx = 'cpp' -- C++ -} - ---- --- Table used to determine if a tag kind is a container or not in a specific --- language. --- Top-level keys are language names from the languages table with table --- values. These table values have tag kind keys with boolean values indicating --- if they are containers or not. --- @class table --- @name container --- @return true if the tag kind is a container. --- @see language -local container = { - lua = {}, - ruby = { c = true, m = true }, - cpp = { c = true, g = true, s = true } -} - ---- --- Table used to determine if a construct name is a container or not in a --- specific language. --- Top-level keys are language names from the languages table with table --- values. These table values have construct name keys with boolean values --- indicating if they are containers or not. --- @class table --- @name container_construct --- @return true if the construct name is a container. --- @see language -local container_construct = { - lua = {}, - ruby = { class = true, module = true }, - cpp = { class = true, enum = true, struct = true } -} - ---- Matches 'ctags:[/absolute/path/to/ctags/file]' -function matches(entry_text) - return entry_text:sub(1, 5) == 'ctags' -end - ---- --- If not expanding, creates the entire tree; otherwise returns the child table --- of the parent being expanded. -function get_contents_for(full_path, expanding) - local ctags_file = full_path[1]:sub(7) -- ignore 'ctags:' - local f - if #ctags_file == 0 then - tags = {} - current_file = nil - current_dir = '' -- ctags file will specify absolute paths - os.execute('ctags -f "'..FILE_OUT..'" '..(buffer.filename or '')) - f = io.open(FILE_OUT, 'rb') - if not f then return {} end - elseif not expanding then - tags = {} - current_file = ctags_file - current_dir = ctags_file:match('^.+/') -- ctags file dirname - f = io.open(ctags_file, 'rb') - if not f then return {} end - else - local parent = tags - for i = 2, #full_path do - local identifier = full_path[i] - if not parent[identifier] then return {} end - parent = parent[identifier].children - end - return parent - end - for line in f:lines() do - if line:sub(1, 2) ~= '!_' then - -- Parse ctags line to get identifier attributes. - local name, filepath, pattern, line_num, ext - name, filepath, pattern, ext = - line:match('^([^\t]+)\t([^\t]+)\t/^(.+)$/;"\t(.*)$') - if not name then - name, filepath, line_num, ext = - line:match('^([^\t]+)\t([^\t]+)\t(%d+);"\t(.*)$') - end - -- If the ctag line is parsed correctly, create the entry. - if name and #name > 0 then - local entry = {} - local file_ext = filepath:match('%.([^.]+)$') - local lang = language[file_ext] - if lang then - -- Parse the extension fields for details on if this identifier is a - -- child or parent and where to put it. - local fields = {} - --print(ext) - for key, val in ext:gmatch('([^:%s]+):?(%S*)') do - if #val == 0 and #key == 1 then -- kind - if container[lang][key] then - -- This identifier is a container. Place it in the toplevel of - -- tags. - entry.parent = true - entry.children = {} - if tags[name] then - -- If previously defined by a child, preserve the children - -- field. - entry.children = tags[name].children - end - tags[name] = entry - entry.set = true - end - entry.pixbuf = pixbuf[lang][key] - elseif container_construct[lang][key] then - -- This identifier belongs to a container, so define the - -- container if it hasn't been already and place this identifier - -- in it. Just in case there is no ctag entry for container later - -- on, define 'parent' and 'text'. - if not tags[val] then - tags[val] = { parent = true, text = val } - end - local parent = tags[val] - if not parent.children then parent.children = {} end - parent.children[name] = entry -- add to parent - entry.set = true - end - end - entry.text = name - -- The following keys are ignored by caller. - entry.filepath = - filepath:sub(1, 1) == '/' and filepath or current_dir..filepath - entry.pattern = pattern - entry.line_num = line_num - if not entry.set then tags[name] = entry end - else - print(string.format(locale.PM_BROWSER_CTAGS_BAD_EXT, file_ext)) - end - else - print(string.format(locale.PM_BROWSER_CTAGS_UNMATCHED, line)) - end - end - end - f:close() - return tags -end - -function perform_action(selected_item) - local item = tags - for i = 2, #selected_item do - local identifier = selected_item[i] - item = item[identifier] - if item.children then item = item.children end - end - if item.pattern then - local buffer_text = buffer:get_text(buffer.length) - local search_text = item.pattern:gsub('\\/', '/') - local s = buffer_text:find(search_text, 1, true) - if s then - textadept.io.open(item.filepath) - local line = buffer:line_from_position(s) - buffer:ensure_visible_enforce_policy(line) - buffer:goto_line(line) - else - error( - string.format(locale.PM_BROWSER_CTAGS_NOT_FOUND, item.text)) - end - elseif item.line_num then - textadept.io.open(item.filepath) - buffer:goto_line(item.line_num - 1) - end - view:focus() -end - -function get_context_menu(selected_item) - -end - -function perform_menu_action(menu_id, selected_item) - -end - -local function update_view() - if matches(textadept.pm.entry_text) then - if buffer.filename then - textadept.pm.activate() - else - textadept.pm.clear() - end - end -end -textadept.events.add_handler('file_opened', update_view) -textadept.events.add_handler('buffer_deleted', update_view) -textadept.events.add_handler('buffer_after_switch', update_view) -textadept.events.add_handler('save_point_reached', update_view) diff --git a/core/ext/pm/file_browser.lua b/core/ext/pm/file_browser.lua deleted file mode 100644 index 69d3fe76..00000000 --- a/core/ext/pm/file_browser.lua +++ /dev/null @@ -1,111 +0,0 @@ --- Copyright 2007-2010 Mitchell mitchell<att>caladbolg.net. See LICENSE. - -local textadept = _G.textadept -local locale = _G.locale - ---- --- File browser for the Textadept project manager. --- It is enabled by providing the absolute path to a directory in the project --- manager entry field. -module('textadept.pm.browsers.file', package.seeall) - -if not RESETTING then textadept.pm.add_browser(not WIN32 and '/' or 'C:\\') end - -local lfs = require 'lfs' -local os = require 'os' - -show_dot_files = false - -function matches(entry_text) - if not WIN32 then - return entry_text:sub(1, 1) == '/' - else - return entry_text:match('[A-Za-z]:[\\/]') - end -end - -function get_contents_for(full_path) - local iconv = textadept.iconv - local dir = {} - local dirpath = iconv(table.concat(full_path, '/'), _CHARSET, 'UTF-8') - local path = lfs.attributes(dirpath) - if path and path.mode == 'directory' then - local invalid_file = show_dot_files and '^%.%.?$' or '^%.' - for filename in lfs.dir(dirpath) do - if not filename:find(invalid_file) then - local utf8_filename = iconv(filename, 'UTF-8', _CHARSET) - dir[utf8_filename] = { text = utf8_filename } - if lfs.attributes(dirpath..'/'..filename, 'mode') == 'directory' then - dir[utf8_filename].parent = true - dir[utf8_filename].pixbuf = 'gtk-directory' - end - end - end - end - return dir -end - -function perform_action(selected_item) - local utf8_filepath = table.concat(selected_item, '/') - textadept.io.open(utf8_filepath) - view:focus() -end - -local ID = { CHANGE_DIR = 1, FILE_INFO = 2, SHOW_DOT_FILES = 3 } - -function get_context_menu(selected_item) - return { - { 'separator', 0 }, -- make it harder to click 'Change Directory' by mistake - { locale.PM_BROWSER_FILE_CD, ID.CHANGE_DIR }, - { locale.PM_BROWSER_FILE_INFO, ID.FILE_INFO }, - { locale.PM_BROWSER_FILE_SHOW_DOT_FILES, ID.SHOW_DOT_FILES }, - } -end - -function perform_menu_action(menu_id, selected_item) - local utf8_filepath = table.concat(selected_item, '/'):gsub('[/\\]+', '/') - local filepath = textadept.iconv(utf8_filepath, _CHARSET, 'UTF-8') - if menu_id == ID.CHANGE_DIR then - textadept.pm.entry_text = utf8_filepath - textadept.pm.activate() - elseif menu_id == ID.FILE_INFO then - local date_format = '%D %T' - local attr = lfs.attributes(filepath) - local out = - string.format(locale.PM_BROWSER_FILE_DATA, - attr.mode, attr.size, attr.uid, attr.gid, attr.dev, - os.date(date_format, attr.access), - os.date(date_format, attr.modification), - os.date(date_format, attr.change)) - textadept.dialog('textbox', - '--informative-text', - string.format(locale.PM_BROWSER_FILE_INFO_TEXT, - utf8_filepath), - '--text', out, - '--button1', locale.PM_BROWSER_FILE_INFO_OK) - elseif menu_id == ID.SHOW_DOT_FILES then - show_dot_files = not show_dot_files - textadept.pm.activate() - end -end - --- load the dropped directory (if any) into the file browser; events.lua's --- "uri_dropped" handler already opens dropped files -textadept.events.add_handler('uri_dropped', - function(utf8_uris) - local lfs = require 'lfs' - for utf8_uri in utf8_uris:gmatch('[^\r\n\f]+') do - if utf8_uri:find('^file://') then - utf8_uri = utf8_uri:match('^file://([^\r\n\f]+)') - utf8_uri = utf8_uri:gsub('%%(%x%x)', - function(hex) return string.char(tonumber(hex, 16)) end) - if WIN32 then utf8_uri = utf8_uri:sub(2, -1) end -- ignore leading '/' - local uri = textadept.iconv(utf8_uri, _CHARSET, 'UTF-8') - if lfs.attributes(uri).mode == 'directory' then - textadept.pm.add_browser(utf8_uri) - textadept.pm.entry_text = utf8_uri - textadept.pm.activate() - end - end - end - end) diff --git a/core/ext/pm/modules_browser.lua b/core/ext/pm/modules_browser.lua deleted file mode 100644 index 1d615e76..00000000 --- a/core/ext/pm/modules_browser.lua +++ /dev/null @@ -1,210 +0,0 @@ --- Copyright 2007-2010 Mitchell mitchell<att>caladbolg.net. See LICENSE. - -local textadept = _G.textadept -local locale = _G.locale - ---- --- Modules browser for the Textadept project manager. --- It is enabled with the prefix 'modules' in the project manager entry field. -module('textadept.pm.browsers.modules', package.seeall) - -if not RESETTING then textadept.pm.add_browser('modules') end - -local lfs = require 'lfs' -local os = require 'os' - -local INIT = [[ --- The $1 module. --- It provides utilities for editing $2 code. -module('_m.$1', package.seeall) - -if type(_G.snippets) == 'table' then --- Container for $2-specific snippets. --- @class table --- @name snippets.$1 - _G.snippets.$1 = {} -end - -if type(_G.keys) == 'table' then --- Container for $2-specific key commands. --- @class table --- @name keys.$1 - _G.keys.$1 = {} -end - -require '$1.commands' -require '$1.snippets' - -function set_buffer_properties() - -end -]] - -local SNIPPETS = [[ --- Snippets for the $1 module. -module('_m.$1.snippets', package.seeall) - -local snippets = _G.snippets - -if type(snippets) == 'table' then - snippets.$1 = {} -end -]] - -local COMMANDS = [[ --- Commands for the $1 module. -module('_m.$1.commands', package.seeall) - --- $2-specific key commands. -local keys = _G.keys -if type(keys) == 'table' then - keys.$1 = { - al = { - m = { textadept.io.open, - textadept.iconv(_USERHOME..'/modules/$1/init.lua', - 'UTF-8', _CHARSET) }, - }, - } -end -]] - -function matches(entry_text) - return entry_text:sub(1, 7) == 'modules' -end - -function get_contents_for(full_path) - local dir = {} - local iconv = textadept.iconv - if #full_path == 1 and full_path[1] == 'modules' then - -- toplevel modules - local dirpaths = { - iconv(_USERHOME..'/modules', _CHARSET, 'UTF-8'), - iconv(_HOME..'/modules', _CHARSET, 'UTF-8') - } - for _, dirpath in ipairs(dirpaths) do - if lfs.attributes(dirpath) then - for filename in lfs.dir(dirpath) do - local filepath = dirpath..'/'..filename - if lfs.attributes(filepath, 'mode') == 'directory' and - not filename:find('^%.') then - dir[filepath] = { - parent = true, - pixbuf = 'gtk-directory', - text = iconv(filename, 'UTF-8', _CHARSET) - } - end - end - end - end - else - -- expanding a module - local dirpath = iconv(full_path[#full_path], _CHARSET, 'UTF-8') - for filename in lfs.dir(dirpath) do - if not filename:find('^%.') then - local filepath = dirpath..'/'..filename - dir[filepath] = { text = iconv(filename, 'UTF-8', _CHARSET) } - if lfs.attributes(filepath, 'mode') == 'directory' then - dir[filepath].parent = true - dir[filepath].pixbuf = 'gtk-directory' - end - end - end - end - return dir -end - -function perform_action(selected_item) - local filepath = selected_item[#selected_item] - textadept.io.open(filepath) - view:focus() -end - -local ID = { - NEW = 1, DELETE = 2, CONF_MIME_TYPES = 3, CONF_KEY_COMMANDS = 4, RELOAD = 5 -} - -function get_context_menu(selected_item) - return { - { locale.PM_BROWSER_MODULE_NEW, ID.NEW }, - { locale.PM_BROWSER_MODULE_DELETE, ID.DELETE }, - { locale.PM_BROWSER_MODULE_CONF_MIME_TYPES, ID.CONF_MIME_TYPES }, - { locale.PM_BROWSER_MODULE_CONF_KEY_COMMANDS, ID.CONF_KEY_COMMANDS }, - { 'separator', 0 }, - { locale.PM_BROWSER_MODULE_RELOAD, ID.RELOAD }, - } -end - -function perform_menu_action(menu_id, selected_item) - if menu_id == ID.NEW then - local status, module_name = - textadept.dialog('standard-inputbox', - '--title', locale.PM_BROWSER_MODULE_NEW_TITLE, - '--informative-text', - locale.PM_BROWSER_MODULE_NEW_INFO_TEXT - ):match('^(%d)%s+([^\n]+)%s+$') - if status ~= '1' then return end - local status, lang_name = - textadept.dialog('standard-inputbox', - '--title', locale.PM_BROWSER_MODULE_NEW_LANG_TITLE, - '--informative-text', - locale.PM_BROWSER_MODULE_NEW_LANG_INFO_TEXT - ):match('^(%d)%s+([^\n]+)%s+$') - if status ~= '1' then return end - lfs.mkdir(_USERHOME..'/modules') - local module_dir = _USERHOME..'/modules/'..module_name - if lfs.mkdir(module_dir) then - -- write init.lua from template - local f = io.open(module_dir..'/init.lua', 'wb') - local out = INIT:gsub('$1', module_name):gsub('$2', lang_name) - f:write(out) - f:close() - -- write snippets.lua from template - f = io.open(module_dir..'/snippets.lua', 'wb') - out = SNIPPETS:gsub('$1', module_name):gsub('$2', lang_name) - f:write(out) - f:close() - -- write commands.lua from template - f = io.open(module_dir..'/commands.lua', 'wb') - out = COMMANDS:gsub('$1', module_name):gsub('$2', lang_name) - f:write(out) - f:close() - else - textadept.dialog('ok-msgbox', - '--text', locale.PM_BROWSER_MODULE_NEW_ERROR, - '--informative-text', - locale.PM_BROWSER_MODULE_NEW_ERROR_TEXT, - '--no-cancel') - return - end - elseif menu_id == ID.DELETE then - local dirpath = selected_item[2] - if textadept.dialog('yesno-msgbox', - '--text', locale.PM_BROWSER_MODULE_DELETE_TITLE, - '--informative-text', - string.format(locale.PM_BROWSER_MODULE_DELETE_TEXT, - dirpath:match('[^/\\]+$')), - '--no-cancel', - '--no-newline') == '1' then - local function remove_directory(dirpath) - for name in lfs.dir(dirpath) do - if not name:find('^%.%.?$') then os.remove(dirpath..'/'..name) end - end - lfs.rmdir(dirpath) - end - remove_directory(dirpath) - else - return - end - elseif menu_id == ID.CONF_MIME_TYPES then - textadept.io.open( - textadept.iconv(_HOME..'/core/ext/mime_types.lua', 'UTF-8', _CHARSET)) - elseif menu_id == ID.CONF_KEY_COMMANDS then - if textadept.key_commands then - textadept.io.open( - textadept.iconv(_HOME..'/core/ext/key_commands.lua', 'UTF-8', _CHARSET)) - end - elseif menu_id == ID.RELOAD then - textadept.reset() - end - textadept.pm.activate() -end diff --git a/core/locale.conf b/core/locale.conf index e6595a53..abbaaebd 100644 --- a/core/locale.conf +++ b/core/locale.conf @@ -111,6 +111,10 @@ ERR_BUFFER_EXPECTED "Buffer argument expected." % "The indexed buffer is not the focused one." ERR_BUFFER_NOT_FOCUSED "The indexed buffer is not the focused one." +% core/init.lua +% "Switch Buffers" +SWITCH_BUFFERS "Switch Buffers" + % core/ext/find.lua % Search wrapped FIND_SEARCH_WRAPPED "Search wrapped" @@ -627,114 +631,6 @@ MENU_SAVE_SESSION_TITLE "Save Session" % "Unknown command: " MENU_UNKNOWN_COMMAND "Unknown command: " -% core/ext/pm/buffer_browser.lua -% "gtk-new" -PM_BROWSER_BUFFER_NEW "gtk-new" - -% core/ext/pm/buffer_browser.lua -% "gtk-open" -PM_BROWSER_BUFFER_OPEN "gtk-open" - -% core/ext/pm/buffer_browser.lua -% "gtk-save" -PM_BROWSER_BUFFER_SAVE "gtk-save" - -% core/ext/pm/buffer_browser.lua -% "gtk-save-as" -PM_BROWSER_BUFFER_SAVEAS "gtk-save-as" - -% core/ext/pm/buffer_browser.lua -% "gtk-close" -PM_BROWSER_BUFFER_CLOSE "gtk-close" - -% core/ext/pm/ctags.lua -% "Extension "%s" not recognized" -PM_BROWSER_CTAGS_BAD_EXT "Extension "%s" not recognized." - -% core/ext/pm/ctags.lua -% "Unmatched ctag: %s" -PM_BROWSER_CTAGS_UNMATCHED "Unmatched ctag: %s" - -% core/ext/pm/ctags.lua -% ""%s" not found." -PM_BROWSER_CTAGS_NOT_FOUND ""%s" not found." - -% core/ext/pm/file_browser.lua -% "_Change Directory" -PM_BROWSER_FILE_CD "_Change Directory" - -% core/ext/pm/file_browser.lua -% "File _Info" -PM_BROWSER_FILE_INFO "File _Info" - -% core/ext/pm/file_browser.lua -% "Mode:\t%s\nSize:\t%s\nUID:\t%s\nGID:\t%s\nDevice:\t%s\nAccessed:\t%sModified:\t%s\nChanged:\t%s\n" -PM_BROWSER_FILE_DATA "Mode:\t%s\nSize:\t%s\nUID:\t%s\nGID:\t%s\nDevice:\t%s\nAccessed:\t%sModified:\t%s\nChanged:\t%s\n" - -% core/ext/pm/file_browser.lua -% "File info for "%s"" -PM_BROWSER_FILE_INFO_TEXT "File info for "%s"" - -% core/ext/pm/file_browser.lua -% "OK" -PM_BROWSER_FILE_INFO_OK "OK" - -% core/ext/pm/file_browser.lua -% "Show Dot Files" -PM_BROWSER_FILE_SHOW_DOT_FILES "Show _Dot Files" - -% core/ext/pm/modules_browser.lua -% "_New Language Module" -PM_BROWSER_MODULE_NEW "_New Language Module" - -% core/ext/pm/modules_browser.lua -% "_Delete Module" -PM_BROWSER_MODULE_DELETE "_Delete Module" - -% core/ext/pm/modules_browser.lua -% "Configure _MIME Types" -PM_BROWSER_MODULE_CONF_MIME_TYPES "Configure _MIME Types" - -% core/ext/pm/modules_browser.lua -% "Configure _Key Commands" -PM_BROWSER_MODULE_CONF_KEY_COMMANDS "Configure _Key Commands" - -% core/ext/pm/modules_browser.lua -% "_Reload Modules" -PM_BROWSER_MODULE_RELOAD "_Reload Modules" - -% core/ext/pm/modules_browser.lua -% "Module Name" -PM_BROWSER_MODULE_NEW_TITLE "Module Name" - -% core/ext/pm/modules_browser.lua -% "Module name:" -PM_BROWSER_MODULE_NEW_INFO_TEXT "Module name:" - -% core/ext/pm/modules_browser.lua -% "Language Name" -PM_BROWSER_MODULE_NEW_LANG_TITLE "Language Name" - -% core/ext/pm/modules_browser.lua -% "Language name:" -PM_BROWSER_MODULE_NEW_LANG_INFO_TEXT "Language name:" - -% core/ext/pm/modules_browser.lua -% "Error" -PM_BROWSER_MODULE_NEW_ERROR "Error" - -% core/ext/pm/modules_browser.lua -% "A module by that name already exists or you\ndo not have permission to create the module." -PM_BROWSER_MODULE_NEW_ERROR_TEXT "A module by that name already exists or you\ndo not have permission to create the module." - -% core/ext/pm/modules_browser.lua -% "Delete Module?" -PM_BROWSER_MODULE_DELETE_TITLE "Delete Module?" - -% core/ext/pm/modules_browser.lua -% "Are you sure you want to permanently delete\nthe "%s" module?" -PM_BROWSER_MODULE_DELETE_TEXT "Are you sure you want to permanently delete\nthe "%s" module?" - % modules/textadept/editing.lua % "Go To" M_TEXTADEPT_EDITING_GOTO_TITLE "Go To" @@ -28,13 +28,6 @@ require 'ext/command_entry' -- provides tab-completion for the command entry require 'ext/mime_types' -- provides support for language detection based on -- the file; loads its language-specific module if -- it exists -require 'ext/pm' -- provides the dynamic browser (side pane) functionality -require 'ext/pm.buffer_browser' -- buffer browser -require 'ext/pm.file_browser' -- file browser -require 'ext/pm.modules_browser' -- modules browser -if not WIN32 then - require 'ext/pm.ctags_browser' -- ctags browser -end -- Generic modules to load on startup. require 'textadept' @@ -76,11 +69,5 @@ if not RESETTING then if not filename:find('^~?/') then filename = base_dir..filename end textadept.io.open(filename) end - - -- read only the Project Manager session settings - if not _m.textadept.session.load(nil, true) then - textadept.pm.entry_text = 'buffers' - textadept.pm.activate() - end end end diff --git a/modules/textadept/session.lua b/modules/textadept/session.lua index 4276448d..a867ddf5 100644 --- a/modules/textadept/session.lua +++ b/modules/textadept/session.lua @@ -26,64 +26,54 @@ SAVE_ON_QUIT = true -- project manager details. -- @param filename The absolute path to the session file to load. Defaults to -- DEFAULT_SESSION if not specified. --- @param only_pm Flag indicating whether or not to load only the Project --- Manager session settings. Defaults to false. -- @return true if the session file was opened and read; false otherwise. -- @usage _m.textadept.session.load(filename) -function load(filename, only_pm) +function load(filename) local f = io.open(filename or DEFAULT_SESSION, 'rb') - if not only_pm and not f then + if not f then if not textadept.io.close_all() then return false end end if not f then return false end local current_view, splits = 1, { [0] = {} } for line in f:lines() do - if not only_pm then - if line:find('^buffer:') then - local anchor, current_pos, first_visible_line, filename = - line:match('^buffer: (%d+) (%d+) (%d+) (.+)$') - if not filename:find('^%[.+%]$') then - textadept.io.open(filename or '') - else - textadept.new_buffer() - buffer._type = filename - end - -- Restore saved buffer selection and view. - local anchor = tonumber(anchor) or 0 - local current_pos = tonumber(current_pos) or 0 - local first_visible_line = tonumber(first_visible_line) or 0 - local buffer = buffer - buffer._anchor, buffer._current_pos = anchor, current_pos - buffer._first_visible_line = first_visible_line - buffer:line_scroll(0, - buffer:visible_from_doc_line(first_visible_line)) - buffer:set_sel(anchor, current_pos) - elseif line:find('^%s*split%d:') then - local level, num, type, size = - line:match('^(%s*)split(%d): (%S+) (%d+)') - local view = splits[#level] and splits[#level][tonumber(num)] or view - splits[#level + 1] = { view:split(type == 'true') } - splits[#level + 1][1].size = tonumber(size) -- could be 1 or 2 - elseif line:find('^%s*view%d:') then - local level, num, buf_idx = line:match('^(%s*)view(%d): (%d+)$') - local view = splits[#level][tonumber(num)] or view - buf_idx = tonumber(buf_idx) - if buf_idx > #textadept.buffers then buf_idx = #textadept.buffers end - view:goto_buffer(buf_idx) - elseif line:find('^current_view:') then - local view_idx = line:match('^current_view: (%d+)') - current_view = tonumber(view_idx) or 1 + if line:find('^buffer:') then + local anchor, current_pos, first_visible_line, filename = + line:match('^buffer: (%d+) (%d+) (%d+) (.+)$') + if not filename:find('^%[.+%]$') then + textadept.io.open(filename or '') + else + textadept.new_buffer() + buffer._type = filename end + -- Restore saved buffer selection and view. + local anchor = tonumber(anchor) or 0 + local current_pos = tonumber(current_pos) or 0 + local first_visible_line = tonumber(first_visible_line) or 0 + local buffer = buffer + buffer._anchor, buffer._current_pos = anchor, current_pos + buffer._first_visible_line = first_visible_line + buffer:line_scroll(0, + buffer:visible_from_doc_line(first_visible_line)) + buffer:set_sel(anchor, current_pos) + elseif line:find('^%s*split%d:') then + local level, num, type, size = + line:match('^(%s*)split(%d): (%S+) (%d+)') + local view = splits[#level] and splits[#level][tonumber(num)] or view + splits[#level + 1] = { view:split(type == 'true') } + splits[#level + 1][1].size = tonumber(size) -- could be 1 or 2 + elseif line:find('^%s*view%d:') then + local level, num, buf_idx = line:match('^(%s*)view(%d): (%d+)$') + local view = splits[#level][tonumber(num)] or view + buf_idx = tonumber(buf_idx) + if buf_idx > #textadept.buffers then buf_idx = #textadept.buffers end + view:goto_buffer(buf_idx) + elseif line:find('^current_view:') then + local view_idx = line:match('^current_view: (%d+)') + current_view = tonumber(view_idx) or 1 end if line:find('^size:') then local width, height = line:match('^size: (%d+) (%d+)$') if width and height then textadept.size = { width, height } end - elseif line:find('^pm:') then - local width, cursor, text = line:match('^pm: (%d+) ([%d:]+) (.*)$') - textadept.pm.width = width or 0 - textadept.pm.entry_text = text or '' - textadept.pm.activate() - if cursor then textadept.pm.cursor = cursor end end end f:close() @@ -154,9 +144,6 @@ function save(filename) -- Write out other things. local size = textadept.size session[#session + 1] = ("size: %d %d"):format(size[1], size[2]) - local pm = textadept.pm - session[#session + 1] = - ("pm: %d %s %s"):format(pm.width, pm.cursor or '0', pm.entry_text) -- Write the session. local f = io.open(filename or textadept.session_file or DEFAULT_SESSION, 'wb') if f then diff --git a/src/lua_interface.c b/src/lua_interface.c index acdb4524..7752dcc5 100644 --- a/src/lua_interface.c +++ b/src/lua_interface.c @@ -42,7 +42,6 @@ static int l_buffer_mt_index(lua_State *), l_buffer_mt_newindex(lua_State *), l_bufferp_mt_index(lua_State *), l_bufferp_mt_newindex(lua_State *), l_view_mt_index(lua_State *), l_view_mt_newindex(lua_State *), l_ta_mt_index(lua_State *), l_ta_mt_newindex(lua_State *), - l_pm_mt_index(lua_State *), l_pm_mt_newindex(lua_State *), l_find_mt_index(lua_State *), l_find_mt_newindex(lua_State *), l_ce_mt_index(lua_State *), l_ce_mt_newindex(lua_State *); @@ -53,9 +52,6 @@ static int l_cf_buffer_delete(lua_State *), l_cf_buffer_text_range(lua_State *), l_cf_ta_goto_window(lua_State *), l_cf_view_goto_buffer(lua_State *), l_cf_ta_gtkmenu(lua_State *), l_cf_ta_iconv(lua_State *), l_cf_ta_reset(lua_State *), l_cf_ta_quit(lua_State *), - l_cf_pm_activate(lua_State *), l_cf_pm_add_browser(lua_State *), - l_cf_pm_clear(lua_State *), l_cf_pm_fill(lua_State *), - l_cf_pm_focus(lua_State *), l_cf_pm_show_context_menu(lua_State *), l_cf_find_focus(lua_State *), l_cf_find_next(lua_State *), l_cf_find_prev(lua_State *), l_cf_find_replace(lua_State *), l_cf_find_replace_all(lua_State *), l_cf_ce_focus(lua_State *), @@ -93,15 +89,6 @@ int l_init(int argc, char **argv, int reinit) { lua_newtable(lua); lua_newtable(lua); - l_cfunc(lua, l_cf_pm_activate, "activate"); - l_cfunc(lua, l_cf_pm_add_browser, "add_browser"); - l_cfunc(lua, l_cf_pm_clear, "clear"); - l_cfunc(lua, l_cf_pm_fill, "fill"); - l_cfunc(lua, l_cf_pm_focus, "focus"); - l_cfunc(lua, l_cf_pm_show_context_menu, "show_context_menu"); - l_mt(lua, "_pm_mt", l_pm_mt_index, l_pm_mt_newindex); - lua_setfield(lua, -2, "pm"); - lua_newtable(lua); l_cfunc(lua, l_cf_find_next, "find_next"); l_cfunc(lua, l_cf_find_prev, "find_prev"); l_cfunc(lua, l_cf_find_focus, "focus"); @@ -701,57 +688,6 @@ void l_ta_popup_context_menu(GdkEventButton *event) { } else lua_pop(lua, 1); } -// Project Manager - -/** - * Creates a Lua table of parent nodes for the given Project Manager treeview - * path and returns a reference to it. - * The first table item is the PM Entry text, the next items are parents of the - * given node in descending order, and the last item is the given node itself. - * The reference can be retrieved using lua_rawgeti. - * @param store The GtkTreeStore of the PM view. - * @param path The GtkTreePath of the node. If NULL, only the PM Entry text is - * contained in the resulting table. - * @return int reference to the created table in LUA_REGISTRYINDEX. - */ -int l_pm_pathtableref(GtkTreeStore *store, GtkTreePath *path) { - lua_newtable(lua); - lua_pushstring(lua, gtk_entry_get_text(GTK_ENTRY(pm_entry))); - lua_rawseti(lua, -2, 1); - if (path) { - GtkTreeIter iter; - while (gtk_tree_path_get_depth(path) > 0) { - char *item = 0; - gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, path); - gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, 1, &item, -1); - lua_pushstring(lua, item); - lua_rawseti(lua, -2, gtk_tree_path_get_depth(path) + 1); - g_free(item); - gtk_tree_path_up(path); - } - } - return luaL_ref(lua, LUA_REGISTRYINDEX); -} - -/** - * Requests a popup context menu for a selected Project Manager item. - * @param event The mouse button event. - */ -void l_pm_popup_context_menu(GdkEventButton *event) { - GtkTreePath *path = NULL; - GtkTreeIter iter; - GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(pm_view)); - GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(pm_view)); - if (gtk_tree_selection_get_selected(sel, NULL, &iter)) - path = gtk_tree_model_get_path(model, &iter); - lua_pushlightuserdata(lua, (GdkEventButton *)event); - int ref = luaL_ref(lua, LUA_REGISTRYINDEX); - l_handle_event("pm_context_menu_request", LUA_TTABLE, - l_pm_pathtableref(GTK_TREE_STORE(model), path), - LUA_TLIGHTUSERDATA, ref, -1); - if (path) gtk_tree_path_free(path); -} - // Lua functions (stack maintenence is unnecessary) /** @@ -1006,54 +942,6 @@ static int l_ta_mt_newindex(lua_State *lua) { return 0; } -static int l_pm_mt_index(lua_State *lua) { - const char *key = lua_tostring(lua, 2); - if (streq(key, "entry_text")) - lua_pushstring(lua, gtk_entry_get_text(GTK_ENTRY(pm_entry))); - else if (streq(key, "width")) { - int pos = - gtk_paned_get_position(GTK_PANED(gtk_widget_get_parent(pm_container))); - lua_pushinteger(lua, pos); - } else if (streq(key, "cursor")) { - GtkTreePath *path = NULL; - gtk_tree_view_get_cursor(GTK_TREE_VIEW(pm_view), &path, NULL); - if (path) { - char *path_str = gtk_tree_path_to_string(path); - lua_pushstring(lua, path_str); - g_free(path_str); - gtk_tree_path_free(path); - } else lua_pushnil(lua); - } else lua_rawget(lua, 1); - return 1; -} - -static int l_pm_mt_newindex(lua_State *lua) { - const char *key = lua_tostring(lua, 2); - if (streq(key, "entry_text")) - gtk_entry_set_text(GTK_ENTRY(pm_entry), lua_tostring(lua, 3)); - else if (streq(key, "width")) - gtk_paned_set_position(GTK_PANED(gtk_widget_get_parent(pm_container)), - luaL_checkinteger(lua, 3)); - else if (streq(key, "cursor")) { - GtkTreePath *path = gtk_tree_path_new_from_string(lua_tostring(lua, 3)); - luaL_argcheck(lua, path, 3, "bad path"); - int *indices = gtk_tree_path_get_indices(path); - GtkTreePath *ipath = gtk_tree_path_new_from_indices(indices[0], -1); - for (int i = 1; i < gtk_tree_path_get_depth(path); i++) - if (gtk_tree_view_row_expanded(GTK_TREE_VIEW(pm_view), ipath) || - gtk_tree_view_expand_row(GTK_TREE_VIEW(pm_view), ipath, FALSE)) - gtk_tree_path_append_index(ipath, indices[i]); - else - break; - GtkTreeViewColumn *col = - gtk_tree_view_get_column(GTK_TREE_VIEW(pm_view), 0); - gtk_tree_view_set_cursor(GTK_TREE_VIEW(pm_view), ipath, col, FALSE); - gtk_tree_path_free(ipath); - gtk_tree_path_free(path); - } else lua_rawset(lua, 1); - return 0; -} - #define toggled(w) gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w)) static int l_find_mt_index(lua_State *lua) { const char *key = lua_tostring(lua, 2); @@ -1293,103 +1181,6 @@ static int l_cf_ta_reset(lua_State *lua) { return 0; } -static int l_cf_pm_activate(lua_State *lua) { - g_signal_emit_by_name(G_OBJECT(pm_entry), "activate"); - return 0; -} - -static int l_cf_pm_add_browser(lua_State *lua) { - GtkWidget *pm_combo = gtk_widget_get_parent(pm_entry); - gtk_combo_box_append_text(GTK_COMBO_BOX(pm_combo), lua_tostring(lua, -1)); - return 0; -} - -static int l_cf_pm_clear(lua_State *lua) { - gtk_tree_store_clear( - GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(pm_view)))); - return 0; -} - -static int l_cf_pm_fill(lua_State *lua) { - luaL_checktype(lua, 1, LUA_TTABLE); - GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(pm_view)); - GtkTreeStore *store = GTK_TREE_STORE(model); - GtkTreeIter initial_iter, *initial_iter_p = NULL; - if (lua_gettop(lua) > 1 && lua_type(lua, 2) == LUA_TSTRING && - gtk_tree_model_get_iter_from_string(model, &initial_iter, - lua_tostring(lua, 2))) - initial_iter_p = &initial_iter; - if (!initial_iter_p) gtk_tree_store_clear(store); - GtkTreeIter iter, child; - lua_pushnil(lua); - while (lua_next(lua, 1)) { - if (lua_istable(lua, -1) && lua_type(lua, -2) == LUA_TSTRING) { - gtk_tree_store_append(store, &iter, initial_iter_p); - gtk_tree_store_set(store, &iter, 1, lua_tostring(lua, -2), -1); - lua_getfield(lua, -1, "parent"); - if (lua_toboolean(lua, -1)) { - gtk_tree_store_append(store, &child, &iter); - gtk_tree_store_set(store, &child, 1, "\0dummy", -1); - } - lua_pop(lua, 1); // parent - lua_getfield(lua, -1, "pixbuf"); - if (lua_isstring(lua, -1)) - gtk_tree_store_set(store, &iter, 0, lua_tostring(lua, -1), -1); - else if (!lua_isnil(lua, -1)) - warn("pm.fill: non-string pixbuf key ignored"); - lua_pop(lua, 1); // pixbuf - lua_getfield(lua, -1, "text"); - gtk_tree_store_set(store, &iter, 2, lua_isstring(lua, -1) ? - lua_tostring(lua, -1) : lua_tostring(lua, -3), -1); - lua_pop(lua, 1); // display text - } else warn("pm.fill: string id key must have table value"); - lua_pop(lua, 1); // value - } - if (initial_iter_p) { - char *item; - gtk_tree_model_iter_nth_child(model, &child, initial_iter_p, 0); - gtk_tree_model_get(model, &child, 1, &item, -1); - if (strcmp((const char *)item, "\0dummy") == 0) - gtk_tree_store_remove(store, &child); - g_free(item); - } - return 0; -} - -static void pm_menu_activate(GtkWidget *menu, gpointer id) { - GtkTreePath *path = NULL; - GtkTreeIter iter; - GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(pm_view)); - GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(pm_view)); - if (gtk_tree_selection_get_selected(sel, NULL, &iter)) - path = gtk_tree_model_get_path(model, &iter); - l_handle_event("pm_menu_clicked", LUA_TNUMBER, GPOINTER_TO_INT(id), - LUA_TTABLE, l_pm_pathtableref(GTK_TREE_STORE(model), path), - -1); - if (path) gtk_tree_path_free(path); -} - -static int l_cf_pm_show_context_menu(lua_State *lua) { - GdkEventButton *event = NULL; - if (lua_gettop(lua) > 1) { - if (lua_isuserdata(lua, 2)) - event = (GdkEventButton *)lua_touserdata(lua, 2); - lua_pop(lua, 1); // userdata - } - luaL_checktype(lua, 1, LUA_TTABLE); - GtkWidget *menu = l_create_gtkmenu(lua, G_CALLBACK(pm_menu_activate), FALSE); - gtk_widget_show_all(menu); - gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, - event ? event->button : 0, - gdk_event_get_time((GdkEvent *)event)); - return 0; -} - -static int l_cf_pm_focus(lua_State *lua) { - pm_toggle_focus(); - return 0; -} - static int l_cf_find_focus(lua_State *lua) { find_toggle_focus(); return 0; diff --git a/src/textadept.c b/src/textadept.c index fa94a469..afa3b9c6 100644 --- a/src/textadept.c +++ b/src/textadept.c @@ -30,27 +30,6 @@ static OSErr w_ae_open(const AppleEvent *, AppleEvent *, long); static OSErr w_ae_quit(const AppleEvent *, AppleEvent *, long); #endif -// Project Manager -GtkWidget *pm_view, *pm_entry, *pm_container; -GtkWidget *pm_create_ui(); -GtkTreeStore *pm_store; - -static int pm_search_equal_func(GtkTreeModel *, int, const char *, - GtkTreeIter *, gpointer); -static int pm_sort_iter_compare_func(GtkTreeModel *, GtkTreeIter *, - GtkTreeIter *, gpointer); -static void pm_entry_activated(GtkWidget *, gpointer); -static void pm_entry_changed(GtkComboBoxEntry *, gpointer); -static gbool pm_keypress(GtkWidget *, GdkEventKey *, gpointer); -static void pm_row_expanded(GtkTreeView *, GtkTreeIter *, GtkTreePath *, - gpointer); -static void pm_row_collapsed(GtkTreeView *, GtkTreeIter *, GtkTreePath *, - gpointer); -static void pm_row_activated(GtkTreeView *, GtkTreePath *, - GtkTreeViewColumn *, gpointer); -static gbool pm_buttonpress(GtkTreeView *, GdkEventButton *, gpointer); -static gbool pm_popup_menu(GtkWidget *, gpointer); - // Find/Replace GtkWidget *findbox, *find_entry, *replace_entry, *fnext_button, *fprev_button, *r_button, *ra_button, *match_case_opt, *whole_word_opt, *lua_opt, @@ -163,14 +142,8 @@ void create_ui() { menubar = gtk_menu_bar_new(); gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 0); - GtkWidget *pane = gtk_hpaned_new(); - gtk_box_pack_start(GTK_BOX(vbox), pane, TRUE, TRUE, 0); - - GtkWidget *pm = pm_create_ui(); - gtk_paned_add1(GTK_PANED(pane), pm); - GtkWidget *hbox = gtk_hbox_new(FALSE, 0); - gtk_paned_add2(GTK_PANED(pane), hbox); + gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0); GtkWidget *editor = new_scintilla_window(0); gtk_box_pack_start(GTK_BOX(hbox), editor, TRUE, TRUE, 0); @@ -551,208 +524,6 @@ static OSErr w_ae_quit(const AppleEvent *event, AppleEvent *reply, long ref) { } #endif -// Project Manager - -/** - * Creates the Project Manager pane. - * It consists of an entry box and a treeview called 'textadept-pm-entry' and - * 'textadept-pm-view' respectively for styling via gtkrc. The treeview model - * consists of a gdk-pixbuf for icons and markup text. - */ -GtkWidget *pm_create_ui() { - pm_container = gtk_vbox_new(FALSE, 1); - - GtkWidget *pm_combo = gtk_combo_box_entry_new_text(); - gtk_combo_box_set_focus_on_click(GTK_COMBO_BOX(pm_combo), FALSE); - pm_entry = gtk_bin_get_child(GTK_BIN(pm_combo)); - gtk_widget_set_name(pm_entry, "textadept-pm-entry"); - gtk_box_pack_start(GTK_BOX(pm_container), pm_combo, FALSE, FALSE, 0); - - pm_store = gtk_tree_store_new(3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); - GtkTreeSortable *sortable = GTK_TREE_SORTABLE(pm_store); - gtk_tree_sortable_set_sort_column_id(sortable, 1, GTK_SORT_ASCENDING); - gtk_tree_sortable_set_sort_func(sortable, 1, pm_sort_iter_compare_func, - GINT_TO_POINTER(1), NULL); - - pm_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(pm_store)); - g_object_unref(pm_store); - gtk_widget_set_name(pm_view, "textadept-pm-view"); - gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(pm_view), FALSE); - gtk_tree_view_set_enable_search(GTK_TREE_VIEW(pm_view), TRUE); - gtk_tree_view_set_search_column(GTK_TREE_VIEW(pm_view), 2); - gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(pm_view), - pm_search_equal_func, NULL, NULL); - - GtkTreeViewColumn *column = gtk_tree_view_column_new(); - GtkCellRenderer *renderer; - renderer = gtk_cell_renderer_pixbuf_new(); // pixbuf - gtk_tree_view_column_pack_start(column, renderer, FALSE); - gtk_tree_view_column_set_attributes(column, renderer, "stock-id", 0, NULL); - renderer = gtk_cell_renderer_text_new(); // markup text - gtk_tree_view_column_pack_start(column, renderer, TRUE); - gtk_tree_view_column_set_attributes(column, renderer, "markup", 2, NULL); - gtk_tree_view_append_column(GTK_TREE_VIEW(pm_view), column); - - GtkWidget *scrolled = gtk_scrolled_window_new(NULL, NULL); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), - GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtk_container_add(GTK_CONTAINER(scrolled), pm_view); - gtk_box_pack_start(GTK_BOX(pm_container), scrolled, TRUE, TRUE, 0); - - signal(pm_entry, "activate", pm_entry_activated); - signal(pm_combo, "changed", pm_entry_changed); - signal(pm_entry, "key-press-event", pm_keypress); - signal(pm_view, "key-press-event", pm_keypress); - signal(pm_view, "row-expanded", pm_row_expanded); - signal(pm_view, "row-collapsed", pm_row_collapsed); - signal(pm_view, "row-activated", pm_row_activated); - signal(pm_view, "button-press-event", pm_buttonpress); - signal(pm_view, "popup-menu", pm_popup_menu); - - return pm_container; -} - -/** - * Toggles the focus between the Project Manager and the current Scintilla - * window. - */ -void pm_toggle_focus() { - gtk_widget_grab_focus( - GTK_WIDGET_HAS_FOCUS(focused_editor) ? pm_entry : focused_editor); -} - -/** - * When searching the Project Manager treeview, matches are tree items that - * contain the search text as a substring. - * @param model The GtkTreeModel for the treeview. - * @param col The column number to use for comparing search text to. - * @param key The search text. - * @param iter The GtkTreeIter for each tree node being compared. - */ -static int pm_search_equal_func(GtkTreeModel *model, int col, const char *key, - GtkTreeIter *iter, gpointer udata) { - const char *text; - gtk_tree_model_get(model, iter, col, &text, -1); - return strstr(text, key) == NULL; // FALSE is really a match like strcmp -} - -/** - * Sorts the Project Manager treeview case sensitively. - * @param model The GtkTreeModel for the treeview. - * @param a The GtkTreeIter for one tree node being compared. - * @param b The GtkTreeIter for the other tree node being compared. - */ -static int pm_sort_iter_compare_func(GtkTreeModel *model, GtkTreeIter *a, - GtkTreeIter *b, gpointer udata) { - char *a_text, *b_text, *p; - gtk_tree_model_get(model, a, 1, &a_text, -1); - gtk_tree_model_get(model, b, 1, &b_text, -1); - if (a_text) for (p = a_text; *p != '\0'; p++) *p = g_ascii_tolower(*p); - if (b_text) for (p = b_text; *p != '\0'; p++) *p = g_ascii_tolower(*p); - int retval = g_strcmp0(a_text, b_text); - g_free(a_text); - g_free(b_text); - return retval; -} - -// Signals - -/** - * Signal for the activation of the Project Manager entry. - * Requests contents for the Project Manager. - */ -static void pm_entry_activated(GtkWidget *entry, gpointer udata) { - l_handle_event("pm_contents_request", LUA_TTABLE, - l_pm_pathtableref(pm_store, NULL), LUA_TNIL, 0, -1); -} - -/** - * Signal for a change of the text in the Project Manager entry. - * Requests contents for the Project Manager. - */ -static void pm_entry_changed(GtkComboBoxEntry *entry, gpointer udata) { - l_handle_event("pm_contents_request", LUA_TTABLE, - l_pm_pathtableref(pm_store, NULL), LUA_TNIL, 0, -1); -} - -/** - * Signal for a Project Manager keypress. - * Currently handled keypresses: - * - Escape - Refocuses the Scintilla view. - */ -static gbool pm_keypress(GtkWidget *pm, GdkEventKey *event, gpointer udata) { - if (event->keyval == 0xff1b) { - gtk_widget_grab_focus(focused_editor); - return TRUE; - } else return FALSE; -} - -/** - * Signal for a Project Manager parent expansion. - * Requests contents for a Project Manager parent node being opened. - * Since a parent is given a dummy child by default in order to indicate that - * it is a parent, that dummy child is removed. - */ -static void pm_row_expanded(GtkTreeView *view, GtkTreeIter *iter, - GtkTreePath *path, gpointer udata) { - char *path_str = gtk_tree_path_to_string(path); - l_handle_event("pm_contents_request", LUA_TTABLE, - l_pm_pathtableref(pm_store, path), LUA_TSTRING, path_str, -1); - g_free(path_str); -} - -/** - * Signal for a Project Manager parent collapse. - * Removes all Project Manager children from a parent node being closed. - * Re-adds a dummy child to indicate this parent is still a parent. It will be - * removed when the parent is re-opened. - */ -static void pm_row_collapsed(GtkTreeView *view, GtkTreeIter *iter, - GtkTreePath *path, gpointer udata) { - GtkTreeIter child; - gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(pm_store), &child, iter, 0); - while (gtk_tree_model_iter_has_child(GTK_TREE_MODEL(pm_store), iter)) - gtk_tree_store_remove(pm_store, &child); - gtk_tree_store_append(pm_store, &child, iter); - gtk_tree_store_set(pm_store, &child, 1, "\0dummy", -1); -} - -/** - * Signal for the activation of a Project Manager node. - * Performs the appropriate action on a selected Project Manager node. - * If the node is a collapsed parent, it is expanded; otherwise the parent is - * collapsed. If the node is not a parent at all, a Lua action is performed. - */ -static void pm_row_activated(GtkTreeView *view, GtkTreePath *path, - GtkTreeViewColumn *column, gpointer udata) { - if (!gtk_tree_view_expand_row(view, path, FALSE)) - if (!gtk_tree_view_collapse_row(view, path)) - l_handle_event("pm_item_selected", LUA_TTABLE, - l_pm_pathtableref(pm_store, path), -1); -} - -/** - * Signal for a Project Manager mouse click. - * If it is a right-click, popup a context menu for the selected item. - * @see l_pm_popup_context_menu - */ -static gbool pm_buttonpress(GtkTreeView *view, GdkEventButton *event, - gpointer udata) { - if (event->type != GDK_BUTTON_PRESS || event->button != 3) return FALSE; - l_pm_popup_context_menu(event); - return TRUE; -} - -/** - * Signal for popping up a Project Manager context menu. - * Typically Shift+F10 activates this event. - * @see l_pm_popup_context_menu - */ -static gbool pm_popup_menu(GtkWidget *view, gpointer udata) { - l_pm_popup_context_menu(NULL); - return TRUE; -} - // Find/Replace #define attach(w, x1, x2, y1, y2, xo, yo, xp, yp) \ diff --git a/src/textadept.h b/src/textadept.h index 202a7dd5..0ec59dff 100644 --- a/src/textadept.h +++ b/src/textadept.h @@ -20,8 +20,8 @@ #include <lauxlib.h> // globals -extern GtkWidget *window, *focused_editor, *command_entry, *pm_container, - *pm_entry, *pm_view, *findbox, *find_entry, *replace_entry, +extern GtkWidget *window, *focused_editor, *command_entry, + *findbox, *find_entry, *replace_entry, *fnext_button, *fprev_button, *r_button, *ra_button, *match_case_opt, *whole_word_opt, *lua_opt, *in_files_opt; extern char *textadept_home; @@ -38,7 +38,6 @@ void split_window(GtkWidget *, int); int unsplit_window(GtkWidget *); void set_menubar(GtkWidget *); void set_statusbar_text(const char *, int); -void pm_toggle_focus(); void find_toggle_focus(); void ce_toggle_focus(); @@ -59,7 +58,4 @@ int l_handle_event(const char *, ...); void l_handle_scnnotification(struct SCNotification *); void l_ta_popup_context_menu(GdkEventButton *); -int l_pm_pathtableref(GtkTreeStore *, GtkTreePath *); -void l_pm_popup_context_menu(GdkEventButton *); - #endif |