diff options
author | mitchell <70453897+667e-11@users.noreply.github.com> | 2013-09-29 21:09:56 -0400 |
---|---|---|
committer | mitchell <70453897+667e-11@users.noreply.github.com> | 2013-09-29 21:09:56 -0400 |
commit | 18d7be2d1eaaef73c56dc850a3172529726d7a34 (patch) | |
tree | 3eeffd78480b6ade940532e8dc3f143304b48cb6 /core | |
parent | ef23e13ac57cf6a8bcb04ccce10d2e5b34feec06 (diff) |
Added new `ui.dialogs` module for more user-friendly dialog support.
As a result, removed `ui.filteredlist()` and changed `io.open_file()` and
`io.snapopen()` APIs to accept tables of files and paths instead of "\n"
delimited strings.
Diffstat (limited to 'core')
-rw-r--r-- | core/.ui.dialogs.luadoc | 415 | ||||
-rw-r--r-- | core/file_io.lua | 128 | ||||
-rw-r--r-- | core/ui.lua | 111 |
3 files changed, 538 insertions, 116 deletions
diff --git a/core/.ui.dialogs.luadoc b/core/.ui.dialogs.luadoc new file mode 100644 index 00000000..dc3e99e8 --- /dev/null +++ b/core/.ui.dialogs.luadoc @@ -0,0 +1,415 @@ +-- Copyright 2007-2013 Mitchell mitchell.att.foicica.com. See LICENSE. +-- This is a DUMMY FILE used for making LuaDoc for built-in functions in the +-- ui.dialogs table. + +--- Provides a set of interactive dialog prompts for user input. +module('ui.dialogs') + +--- +-- Prompts the user with a generic message box dialog defined by dialog options +-- table *options*, returning the index of the selected button or, if +-- *options*.`string_output` is `true`, the selected button's label. +-- If the dialog timed out, returns `0` or `"timeout"`. If the user canceled the +-- dialog, returns `-1` or `"delete"`. +-- @param options Table of key-value option pairs for the message box. +-- +-- * `title`: The dialog's title text. +-- * `text`: The dialog's main message text. +-- * `informative_text`: The dialog's extra informative text. +-- * `icon`: The dialog's GTK stock icon name. Examples are +-- "gtk-dialog-error", "gtk-dialog-info", "gtk-dialog-question", and +-- "gtk-dialog-warning". The dialog does not display an icon by default. +-- * `icon_file`: The dialog's icon file path. This option has no effect when +-- `icon` is set. +-- * `button1`: The right-most button's label. The default value is +-- `_L['_OK']`. +-- * `button2`: The middle button's label. +-- * `button3`: The left-most button's label. This option requires `button2` +-- to be set. +-- * `string_output`: Return the selected button's label or the dialog's exit +-- status instead of the button's index or the exit code. The default value +-- is `false`. +-- * `width`: The pixel width of the dialog. +-- * `height`: The pixel height of the dialog. +-- * `float`: Show the dialog on top of all desktop windows. The default value +-- is `false`. +-- * `timeout`: The number of seconds the dialog waits for the user to select +-- a button before timing out. Dialogs do not time out by default. +-- @return selected button or exit code +-- @usage ui.dialogs.msgbox{title = 'EOL Mode', text = 'Which EOL?', +-- icon = 'gtk-dialog-question', button1 = 'CRLF', button2 = 'CR', +-- button3 = 'LF'} +function msgbox(options) end + +--- +-- Prompts the user with a generic message box dialog defined by dialog options +-- table *options* and with localized "Ok" and "Cancel" buttons, returning the +-- index of the selected button or, if *options*.`string_output` is `true`, the +-- selected button's label. +-- If the dialog timed out, returns `0` or `"timeout"`. If the user canceled the +-- dialog, returns `-1` or `"delete"`. +-- @param options Table of key-value option pairs for the message box. +-- +-- * `title`: The dialog's title text. +-- * `text`: The dialog's main message text. +-- * `informative_text`: The dialog's extra informative text. +-- * `icon`: The dialog's GTK stock icon name. Examples are +-- "gtk-dialog-error", "gtk-dialog-info", "gtk-dialog-question", and +-- "gtk-dialog-warning". The dialog does not display an icon by default. +-- * `icon_file`: The dialog's icon file path. This option has no effect when +-- `icon` is set. +-- * `no_cancel`: Do not display the "Cancel" button. The default value is +-- `false`. +-- * `string_output`: Return the selected button's label or the dialog's exit +-- status instead of the button's index or the exit code. The default value +-- is `false`. +-- * `width`: The pixel width of the dialog. +-- * `height`: The pixel height of the dialog. +-- * `float`: Show the dialog on top of all desktop windows. The default value +-- is `false`. +-- * `timeout`: The number of seconds the dialog waits for the user to select +-- a button before timing out. Dialogs do not time out by default. +-- @return selected button or exit code +function ok_msgbox(options) end + +--- +-- Prompts the user with a generic message box dialog defined by dialog options +-- table *options* and with localized "Yes", "No", and "Cancel" buttons, +-- returning the index of the selected button or, if *options*.`string_output` +-- is `true`, the selected button's label. +-- If the dialog timed out, returns `0` or `"timeout"`. If the user canceled the +-- dialog, returns `-1` or `"delete"`. +-- @param options Table of key-value option pairs for the message box. +-- +-- * `title`: The dialog's title text. +-- * `text`: The dialog's main message text. +-- * `informative_text`: The dialog's extra informative text. +-- * `icon`: The dialog's GTK stock icon name. Examples are +-- "gtk-dialog-error", "gtk-dialog-info", "gtk-dialog-question", and +-- "gtk-dialog-warning". The dialog does not display an icon by default. +-- * `icon_file`: The dialog's icon file path. This option has no effect when +-- `icon` is set. +-- * `no_cancel`: Do not display the "Cancel" button. The default value is +-- `false`. +-- * `string_output`: Return the selected button's label or the dialog's exit +-- status instead of the button's index or the exit code. The default value +-- is `false`. +-- * `width`: The pixel width of the dialog. +-- * `height`: The pixel height of the dialog. +-- * `float`: Show the dialog on top of all desktop windows. The default value +-- is `false`. +-- * `timeout`: The number of seconds the dialog waits for the user to select +-- a button before timing out. Dialogs do not time out by default. +-- @return selected button or exit code +function yesno_msgbox(options) end + +--- +-- Prompts the user with a one-line input box dialog defined by dialog options +-- table *options*, returning the index of the selected button along with the +-- input text or, if *options*.`string_output` is `true`, the selected button's +-- label along with the input text. +-- If the dialog timed out, returns `0` or `"timeout"`. If the user canceled the +-- dialog, returns `-1` or `"delete"`. +-- @param options Table of key-value option pairs for the input box. +-- +-- * `title`: The dialog's title text. +-- * `informative_text`: The dialog's main message text. +-- * `text`: The dialog's initial input text. +-- * `button1`: The right-most button's label. The default value is +-- `_L['_OK']`. +-- * `button2`: The middle button's label. +-- * `button3`: The left-most button's label. This option requires `button2` +-- to be set. +-- * `string_output`: Return the selected button's label or the dialog's exit +-- status instead of the button's index or the exit code. The default value +-- is `false`. +-- * `width`: The pixel width of the dialog. +-- * `height`: The pixel height of the dialog. +-- * `float`: Show the dialog on top of all desktop windows. The default value +-- is `false`. +-- * `timeout`: The number of seconds the dialog waits for the user to select +-- a button before timing out. Dialogs do not time out by default. +-- @return selected button or exit code, input text +-- @usage ui.dialogs.inputbox{title = 'Goto Line', informative_text = 'Line:', +-- text = '1'} +function inputbox(options) end + +--- +-- Prompts the user with a one-line input box dialog defined by dialog options +-- table *options* and with localized "Ok" and "Cancel" buttons, returning the +-- index of the selected button along with the input text or, if +-- *options*.`string_output` is `true`, the selected button's label along with +-- the input text. +-- If the dialog timed out, returns `0` or `"timeout"`. If the user canceled the +-- dialog, returns `-1` or `"delete"`. +-- @param options Table of key-value option pairs for the input box. +-- +-- * `title`: The dialog's title text. +-- * `informative_text`: The dialog's main message text. +-- * `text`: The dialog's initial input text. +-- * `no_cancel`: Do not display the "Cancel" button. The default value is +-- `false`. +-- * `string_output`: Return the selected button's label or the dialog's exit +-- status instead of the button's index or the exit code. The default value +-- is `false`. +-- * `width`: The pixel width of the dialog. +-- * `height`: The pixel height of the dialog. +-- * `float`: Show the dialog on top of all desktop windows. The default value +-- is `false`. +-- * `timeout`: The number of seconds the dialog waits for the user to select +-- a button before timing out. Dialogs do not time out by default. +-- @return selected button or exit code, input text +function standard_inputbux(options) end + +--- +-- Prompts the user with a one-line masked input box dialog defined by dialog +-- options table *options*, returning the index of the selected button along +-- with the input text or, if *options*.`string_output` is `true`, the selected +-- button's label along with the input text. +-- If the dialog timed out, returns `0` or `"timeout"`. If the user canceled the +-- dialog, returns `-1` or `"delete"`. +-- @param options Table of key-value option pairs for the input box. +-- +-- * `title`: The dialog's title text. +-- * `informative_text`: The dialog's main message text. +-- * `text`: The dialog's initial input text. +-- * `button1`: The right-most button's label. The default value is +-- `_L['_OK']`. +-- * `button2`: The middle button's label. +-- * `button3`: The left-most button's label. This option requires `button2` +-- to be set. +-- * `string_output`: Return the selected button's label or the dialog's exit +-- status instead of the button's index or the exit code. The default value +-- is `false`. +-- * `width`: The pixel width of the dialog. +-- * `height`: The pixel height of the dialog. +-- * `float`: Show the dialog on top of all desktop windows. The default value +-- is `false`. +-- * `timeout`: The number of seconds the dialog waits for the user to select +-- a button before timing out. Dialogs do not time out by default. +-- @return selected button or exit code, input text +function secure_inputbox(options) end + +--- +-- Prompts the user with a one-line masked input box dialog defined by dialog +-- options table *options* and with localized "Ok" and "Cancel" buttons, +-- returning the index of the selected button along with the input text or, if +-- *options*.`string_output` is `true`, the selected button's label along with +-- the input text. +-- If the dialog timed out, returns `0` or `"timeout"`. If the user canceled the +-- dialog, returns `-1` or `"delete"`. +-- @param options Table of key-value option pairs for the input box. +-- +-- * `title`: The dialog's title text. +-- * `informative_text`: The dialog's main message text. +-- * `text`: The dialog's initial input text. +-- * `no_cancel`: Do not display the "Cancel" button. The default value is +-- `false`. +-- * `string_output`: Return the selected button's label or the dialog's exit +-- status instead of the button's index or the exit code. The default value +-- is `false`. +-- * `width`: The pixel width of the dialog. +-- * `height`: The pixel height of the dialog. +-- * `float`: Show the dialog on top of all desktop windows. The default value +-- is `false`. +-- * `timeout`: The number of seconds the dialog waits for the user to select +-- a button before timing out. Dialogs do not time out by default. +-- @return selected button or exit code, input text +function secure_standard_inputbox(options) end + +--- +-- Prompts the user with a file selection dialog defined by dialog options +-- table *options*, returning the string file selected or, if +-- *options*.`select_multiple` is `true`, the list of files selected. +-- If the user canceled the dialog, returns `nil`. +-- @param options Table of key-value option pairs for the dialog. +-- +-- * `title`: The dialog's title text. +-- * `with_directory`: The initial filesystem directory to show. +-- * `with_file`: The initially selected filename. This option requires +-- `with_directory` to be set. +-- * `with_extension`: The list of extensions selectable files must have. +-- * `select_multiple`: Allow the user to select multiple files. The default +-- value is `false`. +-- * `select_only_directories`: Only allow the user to select directories. The +-- default value is `false`. +-- @return filename, list of filenames, or nil +-- @usage ui.dialogs.fileselect{title = 'Open C File', with_directory = _HOME, +-- with_extension = {'c', 'h'}, select_multiple = true} +function fileselect(options) end + +--- +-- Prompts the user with a file save dialog defined by dialog options table +-- *options*, returning the string file chosen. +-- If the user canceled the dialog, returns `nil`. +-- @param options Table of key-value option pairs for the dialog. +-- +-- * `title`: The dialog's title text. +-- * `with_directory`: The initial filesystem directory to show. +-- * `with_file`: The initially chosen filename. This option requires +-- `with_directory` to be set. +-- * `with_extension`: The list of extensions selectable files must have. +-- * `no_create_directories`: Prevent the user from creating new directories. +-- The default value is `false`. +-- @return filename or nil +function filesave(options) end + +--- +-- Prompts the user with a multiple-line textbox dialog defined by dialog +-- options table *options*, returning the index of the selected button along +-- with the textbox text if *options*.`editable` is `true` or, if +-- *options*.`string_output` is `true`, the selected button's label along with +-- the textbox text if *options*.`editable` is also `true`. +-- If the dialog timed out, returns `0` or `"timeout"`. If the user canceled the +-- dialog, returns `-1` or `"delete"`. +-- @param options Table of key-value option pairs for the dialog. +-- +-- * `title`: The dialog's title text. +-- * `informative_text`: The dialog's main message text. +-- * `text`: The dialog's initial textbox text. +-- * `text_from_file`: The filename whose contents are loaded into the +-- textbox. This option has no effect when `text` is given. +-- * `button1`: The right-most button's label. The default value is +-- `_L['_OK']`. +-- * `button2`: The middle button's label. +-- * `button3`: The left-most button's label. This option requires `button2` +-- to be set. +-- * `editable`: Allows the user to edit the text in the textbox. The default +-- value is `false`. +-- * `focus_textbox`: Focus the textbox instead of the dialog buttons. The +-- default value is `false`. +-- * `scroll_to`: Where to scroll the textbox text when it is not all visible. +-- The available values are `"top"` and `"bottom"`. The default value is +-- `"top"`. +-- * `selected`: Select all textbox text. The default value is `false`. +-- * `monospaced_font`: Use a monospaced font in the textbox instead of a +-- proportional one. The default value is `false`. +-- * `string_output`: Return the selected button's label or the dialog's exit +-- status instead of the button's index or the exit code. The default value +-- is `false`. +-- * `width`: The pixel width of the dialog. +-- * `height`: The pixel height of the dialog. +-- * `float`: Show the dialog on top of all desktop windows. The default value +-- is `false`. +-- * `timeout`: The number of seconds the dialog waits for the user to select +-- a button before timing out. Dialogs do not time out by default. +-- @return selected button or exit code, textbox text +-- @usage ui.dialogs.textbox{title = 'License Agreement', +-- informative_text = 'You agree to:', text_from_file = _HOME..'/LICENSE'} +function textbox(options) end + +--- +-- Prompts the user with a drop down item selection dialog defined by dialog +-- options table *options*, returning the index of the selected button along +-- with the index of the selected item or, if *options*.`string_output` is +-- `true`, the selected button's label along with the selected item's text. +-- If *options*.`exit_onchange` closed the dialog, returns `4` along with either +-- the index of the selected item or the selected item's text. If the dialog +-- timed out, returns `0` or `"timeout"`. If the user canceled the dialog, +-- returns `-1` or `"delete"`. +-- @param options Table of key-value option pairs for the drop down dialog. +-- +-- * `title`: The dialog's title text. +-- * `text`: The dialog's main message text. +-- * `items`: The list of string items to show in the drop down. +-- * `button1`: The right-most button's label. The default value is +-- `_L['_OK']`. +-- * `button2`: The middle button's label. +-- * `button3`: The left-most button's label. This option requires `button2` +-- to be set. +-- * `exit_onchange`: Close the dialog after selecting a new item. The default +-- value is `false`. +-- * `select`: The index of the initially selected list item. The default +-- value is `1`. +-- * `string_output`: Return the selected button's label or the dialog's exit +-- status along with the selected item's text instead of the button's index +-- or the exit code along with the item's index. The default value is +-- `false`. +-- * `width`: The pixel width of the dialog. +-- * `height`: The pixel height of the dialog. +-- * `float`: Show the dialog on top of all desktop windows. The default value +-- is `false`. +-- * `timeout`: The number of seconds the dialog waits for the user to select +-- a button before timing out. Dialogs do not time out by default. +-- @return selected button or exit code, selected item +-- @usage ui.dialogs.dropdown{title = 'Select Encoding', width = 200, +-- items = io.encodings, string_output = true} +function dropdown(options) end + +--- +-- Prompts the user with a drop down item selection dialog defined by dialog +-- options table *options* and with localized "Ok" and "Cancel" buttons, +-- returning the index of the selected button along with the index of the +-- selected item or, if *options*.`string_output` is `true`, the selected +-- button's label along with the selected item's text. +-- If *options*.`exit_onchange` closed the dialog, returns `4` along with either +-- the index of the selected item or the selected item's text. If the dialog +-- timed out, returns `0` or `"timeout"`. If the user canceled the dialog, +-- returns `-1` or `"delete"`. +-- @param options Table of key-value option pairs for the drop down dialog. +-- +-- * `title`: The dialog's title text. +-- * `text`: The dialog's main message text. +-- * `items`: The list of string items to show in the drop down. +-- * `no_cancel`: Do not display the "Cancel" button. The default value is +-- `false`. +-- * `exit_onchange`: Close the dialog after selecting a new item. The default +-- value is `false`. +-- * `select`: The index of the initially selected list item. The default +-- value is `1`. +-- * `string_output`: Return the selected button's label or the dialog's exit +-- status along with the selected item's text instead of the button's index +-- or the exit code along with the item's index. The default value is +-- `false`. +-- * `width`: The pixel width of the dialog. +-- * `height`: The pixel height of the dialog. +-- * `float`: Show the dialog on top of all desktop windows. The default value +-- is `false`. +-- * `timeout`: The number of seconds the dialog waits for the user to select +-- a button before timing out. Dialogs do not time out by default. +-- @return selected button or exit code, selected item +function standard_dropdown(options) end + +--- +-- Prompts the user with a filtered list item selection dialog defined by dialog +-- options table *options*, returning the index of the selected button along +-- with the index(es) of the selected item(s) (depending on whether or not +-- *options*.`select_multiple` is `true`) or, if *options*.`string_output` is +-- `true`, the selected button's label along with the selected item's or items' +-- text. +-- If the dialog timed out, returns `0` or `"timeout"`. If the user canceled the +-- dialog, returns `-1` or `"delete"`. +-- Spaces in the filter text are treated as wildcards. +-- @param options Table of key-value option pairs for the drop down dialog. +-- +-- * `title`: The dialog's title text. +-- * `text`: The dialog's main message text. +-- * `columns`: The list of string column names for list rows. +-- * `items`: The list of string items to show in the drop down. +-- * `button1`: The right-most button's label. The default value is +-- `_L['_OK']`. +-- * `button2`: The middle button's label. +-- * `button3`: The left-most button's label. This option requires `button2` +-- to be set. +-- * `select_multiple`: Allow the user to select multiple items. The default +-- value is `false`. +-- * `search_column`: The column number to filter the input text against. The +-- default value is `1`. This option requires `columns` to be set and +-- contain at least *n* column names. +-- * `output_column`: The column number to use for `string_output`. The +-- default value is `1`. This option requires `columns` to be set and +-- contain at least *n* column names. +-- * `string_output`: Return the selected button's label or the dialog's exit +-- status along with the selected item's text instead of the button's index +-- or the exit code along with the item's index. The default value is +-- `false`. +-- * `width`: The pixel width of the dialog. +-- * `height`: The pixel height of the dialog. +-- * `float`: Show the dialog on top of all desktop windows. The default value +-- is `false`. +-- * `timeout`: The number of seconds the dialog waits for the user to select +-- a button before timing out. Dialogs do not time out by default. +-- @return selected button or exit code, selected item or list of selected items +-- @usage ui.dialogs.filteredlist{title = 'Title', columns = {'Foo', 'Bar'}, +-- items = {'a', 'b', 'c', 'd'}} +function filteredlist(options) end diff --git a/core/file_io.lua b/core/file_io.lua index ce3bf8ec..09533196 100644 --- a/core/file_io.lua +++ b/core/file_io.lua @@ -91,22 +91,22 @@ io.boms = { io.encodings = {'UTF-8', 'ASCII', 'ISO-8859-1', 'MacRoman'} --- --- Opens *filenames*, a "\n" delimited string of filenames, or user-selected --- files. +-- Opens *filenames*, a string filename, table of filenames, or user-selected +-- filenames. -- Emits a `FILE_OPENED` event. --- @param filenames Optional string list filenames to open. If `nil`, the user --- is prompted with a fileselect dialog. +-- @param filenames Optional string filename or table of filenames to open. If +-- `nil`, the user is prompted with a fileselect dialog. -- @see _G.events -- @name open_file function io.open_file(filenames) - filenames = filenames or - ui.dialog('fileselect', - '--title', _L['Open'], - '--select-multiple', - '--with-directory', - (buffer.filename or ''):match('^.+[/\\]') or '') - for filename in filenames:gmatch('[^\n]+') do - filename = filename:gsub('^file://', '') + if type(filenames) == 'string' then filenames = {filenames} end + filenames = filenames or ui.dialogs.fileselect{ + title = _L['Open'], select_multiple = true, + with_directory = (buffer.filename or ''):match('^.+[/\\]') + } + if not filenames then return end + for i = 1, #filenames do + local filename = filenames[i]:gsub('^file://', '') if WIN32 then filename = filename:gsub('/', '\\') end for i, buffer in ipairs(_BUFFERS) do if filename == buffer.filename then view:goto_buffer(i) return end @@ -235,14 +235,12 @@ end -- user is prompted for one. -- @name save_file_as function io.save_file_as(filename) - local dir = (buffer.filename or ''):match('^.+[/\\]') or '' - local name = (buffer.filename or ''):match('[^/\\]+$') or '' - filename = filename or ui.dialog('filesave', - '--title', _L['Save'], - '--with-directory', dir, - '--with-file', name:iconv('UTF-8', _CHARSET), - '--no-newline') - if filename == '' then return end + local dir, name = (buffer.filename or ''):match('^(.-[/\\]?)([^/\\]*)$') + filename = filename or ui.dialogs.filesave{ + title = _L['Save'], with_directory = dir, + with_file = name:iconv('UTF-8', _CHARSET) + } + if not filename then return end buffer.filename = filename io.save_file() events.emit(events.FILE_SAVED_AS, filename) @@ -268,15 +266,13 @@ end -- @name close_buffer function io.close_buffer() local filename = buffer.filename or buffer._type or _L['Untitled'] - if buffer.dirty and ui.dialog('msgbox', - '--title', _L['Close without saving?'], - '--text', _L['There are unsaved changes in'], - '--informative-text', - filename:iconv('UTF-8', _CHARSET), - '--icon', 'gtk-dialog-question', - '--button1', _L['_Cancel'], - '--button2', _L['Close _without saving'], - '--no-newline') ~= '2' then + if buffer.dirty and ui.dialogs.msgbox{ + title = _L['Close without saving?'], + text = _L['There are unsaved changes in'], + informative_text = filename:iconv('UTF-8', _CHARSET), + icon = 'gtk-dialog-question', button1 = _L['_Cancel'], + button2 = _L['Close _without saving'] + } ~= 2 then return nil -- returning false can cause unwanted key command propagation end buffer:delete() @@ -306,19 +302,15 @@ local function update_modified_file() if not mod_time or not buffer.mod_time then return end if buffer.mod_time < mod_time then buffer.mod_time = mod_time - if ui.dialog('yesno-msgbox', - '--title', _L['Reload?'], - '--text', _L['Reload modified file?'], - '--informative-text', - ('"%s"\n%s'):format(buffer.filename:iconv('UTF-8', _CHARSET), - _L['has been modified. Reload it?']), - '--icon', 'gtk-dialog-question', - '--button1', _L['_Yes'], - '--button2', _L['_No'], - '--no-cancel', - '--no-newline') == '1' then - io.reload_file() - end + local msg = string.format('"%s"\n%s', + buffer.filename:iconv('UTF-8', _CHARSET), + _L['has been modified. Reload it?']) + local button = ui.dialogs.msgbox{ + title = _L['Reload?'], text = _L['Reload modified file?'], + informative_text = msg, icon = 'gtk-dialog-question', + button1 = _L['_Yes'], button2 = _L['_No'] + } + if button == 1 then io.reload_file() end end end events_connect(events.BUFFER_AFTER_SWITCH, update_modified_file) @@ -342,14 +334,16 @@ function io.open_recent_file() for _, filename in ipairs(io.recent_files) do utf8_filenames[#utf8_filenames + 1] = filename:iconv('UTF-8', _CHARSET) end - local i = ui.filteredlist(_L['Open'], _L['File'], utf8_filenames, true, - CURSES and {'--width', ui.size[1] - 2} or '') - if i then io.open_file(io.recent_files[i + 1]) end + local button, i = ui.dialogs.filteredlist{ + title = _L['Open'], columns = _L['File'], items = utf8_filenames, + width = CURSES and ui.size[1] - 2 or nil + } + if button == 1 and i then io.open_file(io.recent_files[i]) end end --- --- Quickly open files from *paths*, a "\n" delimited string of directory paths, --- using a filtered list dialog. +-- Quickly open files from *paths*, a string directory path or table of +-- directory paths, using a filtered list dialog. -- Files shown in the dialog do not match any pattern in string or table -- *filter*, and, unless *exclude_FILTER* is `true`, `lfs.FILTER` as well. A -- filter table contains Lua patterns that match filenames to exclude, with @@ -358,13 +352,14 @@ end -- pattern that follows. Use a table of raw file extensions assigned to an -- `extensions` key for fast filtering by extension. The number of files in the -- list is capped at `SNAPOPEN_MAX`. --- @param paths String list of directory paths to search. +-- @param paths String directory path or table of directory paths to search. -- @param filter Optional filter for files and folders to exclude. -- @param exclude_FILTER Optional flag indicating whether or not to exclude the -- default filter `lfs.FILTER` in the search. If `false`, adds `lfs.FILTER` to -- *filter*. -- The default value is `false` to include the default filter. --- @param ... Optional additional parameters to pass to `ui.dialog()`. +-- @param opts Optional additional options to pass to +-- `ui.dialogs.filteredlist()`. -- @usage io.snapopen(buffer.filename:match('^.+/')) -- list all files in the -- current file's directory, subject to the default filter -- @usage io.snapopen('/project', '!%.lua$') -- list all Lua files in a project @@ -374,27 +369,32 @@ end -- @see lfs.FILTER -- @see SNAPOPEN_MAX -- @name snapopen -function io.snapopen(paths, filter, exclude_FILTER, ...) +function io.snapopen(paths, filter, exclude_FILTER, opts) + if type(paths) == 'string' then paths = {paths} end local utf8_list = {} - for path in paths:gmatch('[^\n]+') do - lfs.dir_foreach(path, function(file) + for i = 1, #paths do + lfs.dir_foreach(paths[i], function(file) if #utf8_list >= io.SNAPOPEN_MAX then return false end file = file:gsub('^%.[/\\]', ''):iconv('UTF-8', _CHARSET) utf8_list[#utf8_list + 1] = file end, filter, exclude_FILTER) end if #utf8_list >= io.SNAPOPEN_MAX then - ui.dialog('ok-msgbox', - '--title', _L['File Limit Exceeded'], - '--text', - string.format('%d %s %d', io.SNAPOPEN_MAX, - _L['files or more were found. Showing the first'], - io.SNAPOPEN_MAX), - '--icon', 'gtk-dialog-info', - '--button1', _L['_OK']) + local msg = string.format('%d %s %d', io.SNAPOPEN_MAX, + _L['files or more were found. Showing the first'], + io.SNAPOPEN_MAX) + ui.dialogs.msgbox{ + title = _L['File Limit Exceeded'], text = msg, icon = 'gtk-dialog-info' + } end - local width = CURSES and {'--width', ui.size[1] - 2} or '' - local files = ui.filteredlist(_L['Open'], _L['File'], utf8_list, false, - '--select-multiple', width, ...) or '' - io.open_file(files:iconv(_CHARSET, 'UTF-8')) + local options = { + title = _L['Open'], columns = _L['File'], items = utf8_list, + button1 = _L['_OK'], button2 = _L['_Cancel'], select_multiple = true, + string_output = true, width = CURSES and ui.size[1] - 2 or nil + } + if opts then for k, v in pairs(opts) do options[k] = v end end + local button, files = ui.dialogs.filteredlist(options) + if button ~= _L['_OK'] or not files then return end + for i = 1, #files do files[i] = files[i]:iconv(_CHARSET, 'UTF-8') end + io.open_file(files) end diff --git a/core/ui.lua b/core/ui.lua index 8149b9d7..f1ed2e30 100644 --- a/core/ui.lua +++ b/core/ui.lua @@ -70,43 +70,49 @@ function ui._print(buffer_type, ...) pcall(_print, buffer_type, ...) end -- @name print function ui.print(...) ui._print(_L['[Message Buffer]'], ...) end ---- --- Convenience function for `ui.dialog('filteredlist', ...)` with "Ok" and --- "Cancel" buttons that returns the text or index of the selection depending on --- the boolean value of *int_return*. --- *title* is the title of the dialog, *columns* is a list of column names, and --- *items* is a list of items to show. --- @param title The title for the filtered list dialog. --- @param columns A column name or list of column names. --- @param items An item or list of items. --- @param int_return Optional flag indicating whether to return the integer --- index of the selected item in the filtered list or the string selected --- item. A `true` value is not compatible with the `'--select-multiple'` --- option. The default value is `false`. --- @param ... Optional additional parameters to pass to `ui.dialog()`. --- @return Either a string or integer on success; `nil` otherwise. In strings, --- multiple items are separated by newlines. --- @usage ui.filteredlist('Title', 'Foo', {'Bar', 'Baz'}) --- @usage ui.filteredlist('Title', {'Foo', 'Bar'}, {'a', 'b', 'c', 'd'}, false, --- '--output-column', '2') --- @see dialog --- @name filteredlist -function ui.filteredlist(title, columns, items, int_return, ...) - local out = ui.dialog('filteredlist', - '--title', title, - '--button1', _L['_OK'], - '--button2', _L['_Cancel'], - '--no-newline', - int_return and '' or '--string-output', - '--columns', columns, - '--items', items, - ...) - local patt = int_return and '^(%-?%d+)\n(%d+)$' or '^([^\n]+)\n(.+)$' - local response, value = out:match(patt) - if response == (int_return and '1' or _L['_OK']) then - return not int_return and value or tonumber(value) +-- Documentation is in core/.ui.dialogs.luadoc. +ui.dialogs = setmetatable({}, {__index = function(t, k) + -- Wrapper for `ui.dialog(k)`, transforming the given table of arguments into + -- a set of command line arguments and transforming the resulting standard + -- output into Lua objects. + -- @param options Table of key-value command line options for gtdialog. + -- @return Lua objects depending on the dialog kind + return function(options) + if not options.button1 then options.button1 = _L['_OK'] end + if options.select then options.select = options.select - 1 end + -- Transform key-value pairs into command line arguments. + local args = {} + for option, value in pairs(options) do + if value then + args[#args + 1] = '--'..option:gsub('_', '-') + if value ~= true then args[#args + 1] = value end + end + end + -- Call gtdialog, stripping any trailing newline in the standard output. + local result = ui.dialog(k:gsub('_', '-'), table.unpack(args)) + result = result:match('^(.-)\n?$') + -- Depending on the dialog type, transform the result into Lua objects. + if k == 'fileselect' or k == 'filesave' then + if result == '' then return nil end + if k == 'filesave' or not options.select_multiple then return result end + local files = {} + for file in result:gmatch('[^\n]+') do files[#files + 1] = file end + return files + elseif k == 'filteredlist' then + local button, value = result:match('^([^\n]+)\n?(.*)$') + if not options.string_output then button = tonumber(button) end + local items = {} + for item in value:gmatch('[^\n]+') do + items[#items + 1] = options.string_output and item or tonumber(item) + 1 + end + return button, options.select_multiple and items or items[1] + elseif not options.string_output then + local i, value = result:match('^(%-?%d+)\n?(.*)$') + return tonumber(i), k ~= 'dropdown' and value or tonumber(value) + 1 + end + return result:match('([^\n]+)\n(.*)$') end -end +end}) --- -- Prompts the user to select a buffer to switch to. @@ -120,9 +126,11 @@ function ui.switch_buffer() items[#items + 1] = (buffer.dirty and '*' or '')..basename items[#items + 1] = filename end - local i = ui.filteredlist(_L['Switch Buffers'], columns, items, true, - CURSES and {'--width', ui.size[1] - 2} or '--') - if i then view:goto_buffer(i + 1) end + local button, i = ui.dialogs.filteredlist{ + title = _L['Switch Buffers'], columns = columns, items = items, + width = CURSES and ui.size[1] - 2 or nil + } + if button == 1 and i then view:goto_buffer(i) end end --- @@ -357,15 +365,12 @@ events_connect(events.QUIT, function() list[#list + 1] = filename:iconv('UTF-8', _CHARSET) end end - return #list < 1 or ui.dialog('msgbox', - '--title', _L['Quit without saving?'], - '--text', - _L['The following buffers are unsaved:'], - '--informative-text', table.concat(list, '\n'), - '--icon', 'gtk-dialog-question', - '--button1', _L['_Cancel'], - '--button2', _L['Quit _without saving'], - '--no-newline') == '2' + return #list < 1 or ui.dialogs.msgbox{ + title = _L['Quit without saving?'], + text = _L['The following buffers are unsaved:'], + informative_text = table.concat(list, '\n'), icon = 'gtk-dialog-question', + button1 = _L['_Cancel'], button2 = _L['Quit _without saving'] + } == 2 end) events_connect(events.ERROR, ui.print) @@ -388,14 +393,16 @@ local size The functions below are Lua C functions. --- --- Displays a [gtdialog][] of kind *kind* with the given string arguments to --- pass to the dialog and returns a formatted string of the dialog's output. +-- Low-level function for prompting the user with a [gtdialog][]s of kind *kind* +-- with the given string and table arguments, returning a formatted string of +-- the dialog's output. +-- You probably want to use the higher-level functions in the [`ui.dialogs`][] +-- module. -- Table arguments containing strings are allowed and expanded in place. This is -- useful for filtered list dialogs with many items. --- For more information on gtdialog, see [http://foicica.com/gtdialog][]. -- -- [gtdialog]: http://foicica.com/gtdialog/02_Usage.html --- [http://foicica.com/gtdialog]: http://foicica.com/gtdialog +-- [`ui.dialogs`]: ui.dialogs.html -- @param kind The kind of gtdialog. -- @param ... Parameters to the gtdialog. -- @return string gtdialog result. |