Class ui.Editbox
An editbox is a multi-line input widget.
It is the widget you interact with when you use MC’s editor, but you may also embed it in your own dialogs.
Modifying
ui.Editbox:delete(count[, backwards]) | Deletes text at the cursor location. |
ui.Editbox:insert(s) | Inserts a string into the buffer. |
ui.Editbox:load(filepath, [line_number]) | Loads a file into the buffer. |
Reading
ui.Editbox.current_char r | The character on which the cursor stands. |
ui.Editbox.current_word r | The word on which the cursor stands. |
ui.Editbox:get_line([num[, keep_eol]]) | Fetches a line. |
ui.Editbox:lines() | Lines iterator. |
ui.Editbox:sub(i [, j]) | Extracts a substring. |
Meta
ui.Editbox.filename r | The filename associated with the buffer. |
ui.Editbox.fullscreen rw | Whether the editbox is shown fullscreen. |
ui.Editbox:get_markers() | Returns the extents of the selected text. |
ui.Editbox:len() | Returns the size of the buffer. |
ui.Editbox.max_line r | The number of lines in the buffer. |
ui.Editbox.modified rw | Whether the buffer has been modified. |
ui.Editbox.top_line rw | The number of the first line displayed. |
Bookmarks
ui.Editbox:bookmark_clear(line, style) | Clears a bookmark. |
ui.Editbox:bookmark_exists(line, style) | Queries for a bookmark. |
ui.Editbox:bookmark_flush([style]) | Clears all bookmarks. |
ui.Editbox:bookmark_set(line, style) | Sets a bookmark. |
Cursor
ui.Editbox.cursor_col rw | The cursor’s column. |
ui.Editbox.cursor_line rw | The cursor’s line number. |
ui.Editbox.cursor_offs rw | The cursor’s offset within the buffer. |
ui.Editbox.cursor_xoffs rw | The cursor’s offset within the line. |
Syntax
ui.Editbox:add_keyword(s, style[, opts]) | Syntax-highlights a string. |
ui.Editbox:get_style_at(pos) | Returns the style at a certain position. |
ui.Editbox.syntax rw | The buffer’s syntax type. |
i18n
ui.Editbox:is_utf8() | Whether the buffer is UTF-8 encoded. |
ui.Editbox:to_tty(s) | Converts a string, extracted from the buffer, to the terminal’s encoding. |
Static functions
ui.Editbox.options | Editor options. |
Static functions (syntax)
ui.Editbox.get_syntax_list() | Returns a list of all the recognized syntaxes. |
ui.Editbox.search_syntax(keyword) | Searches within the syntax list. |
Events
<<load>> | Triggered when an editbox is opened. |
<<unload>> | Triggered when an editbox is closed. |
Modifying
- ui.Editbox:delete(count[, backwards])
-
Deletes text at the cursor location.
As an example, here’s how to delete the current word (with the help of current_word):
-- Various ways to delete a word. ui.Editbox.bind('f16', function(edt) local whole, part = edt:get_current_word() whole = whole or abort "stand on a word, will ya?" edt:delete(part:len(), true) edt:delete(whole:len() - part:len()) end) ui.Editbox.bind('f16', function(edt) local whole, part = edt:get_current_word() whole = whole or abort "stand on a word, will ya?" edt.cursor_offs = edt.cursor_offs - part:len() edt:delete(whole:len()) end) -- For completeness sake, here's how to do it using commands. But this -- doesn't behave exactly as the above solutions when standing on -- the beginning/end of the word. ui.Editbox.bind('f16', function(edt) edt:command "DeleteToWordBegin" edt:command "DeleteToWordEnd" end)
Parameters:
- count How many bytes to delete.
- backwards Boolean. Whether to “backspace” instead of delete. (optional)
- ui.Editbox:insert(s)
-
Inserts a string into the buffer.
Inserts text at the cursor location (the cursor then moves forward).
-- Insert the current date and time. ui.Editbox.bind("C-y", function(edt) edt:insert(os.date("%Y-%m-%d %H:%M:%S")) end)
Parameters:
- s text to insert (may contain null bytes).
- ui.Editbox:load(filepath, [line_number])
-
Loads a file into the buffer.
(The file does not have to exist.)
Returns:
-
true unless an error occurred (anything that causes an error message to be shown).
Reading
- ui.Editbox.current_char r
-
The character on which the cursor stands.
When called as a method, returns two values.
Returns:
- The character, as a string.
- The character’s numeric code (Unicode, in case of a UTF-8 encoded buffer).
- ui.Editbox.current_word r
-
The word on which the cursor stands.
This is simply a convenience wrapper around utils.text.extract_word (see there for explanation), implemented thus:
function ui.Editbox.meta:get_current_word() return utils.text.extract_word( self.line, self.cursor_xoffs ) end
You may invoke it as a property:
ui.Editbox.bind('C-y', function(edt) alert(edt.current_word) end)
Or you may use the full method syntax (“:get_current_word()”) to also get the portion of the word preceding the cursor:
ui.Editbox.bind('C-y', function(edt) devel.view{edt:get_current_word()} end)
See usage examples at delete.
As a more elaborate example, here’s a very simple implementation of “word completion” for the editor:
--[[ Word-completion for the editor. Stand on a word and hit C-y. You'll be shown a list of all the words in the buffer sharing that prefix. ]] ui.Editbox.bind('C-y', function(edt) local whole, part = edt:get_current_word() if not whole -- cursor is not on a word. or part == "" -- cursor is on start of a word. then abort(T"Please stand on a word (past its first letter).") end local words = utils.table.List {} for word in edt:sub(1):p_gmatch('\\b' .. part .. '[\\w_]+') do words[word] = true end words = words:keys():sort() if #words ~= 0 then local lbox = ui.Listbox{items=words} if ui.Dialog{compact=true}:add(lbox):popup(lbox) then local word = lbox.value edt:insert(word:sub(part:len()+1)) -- We need just the tail of the word. end else tty.beep() -- no completions found. end end)
- ui.Editbox:get_line([num[, keep_eol]])
-
Fetches a line.
Parameters:
- num The line number. Defaults to the cursor’s line. (optional)
- keep_eol Boolean. Whether to keep the EOL at the end. (optional)
- ui.Editbox:lines()
-
Lines iterator.
Iterates over the lines. Returns the line and its number.
-- Highlight all the lines containing "Linux". ui.Editbox.bind('C-y', function(edt) for line, i in edt:lines() do if line:find('Linux') then edt:bookmark_set(i, tty.style('editor.bookmarkfound')) end end end)
- ui.Editbox:sub(i [, j])
-
Extracts a substring.
Extracts a substring from the buffer. The arguments are the same as string.sub’s (negative indices have the same semantics). The indexing is byte-oriented (not character-oriented).
see len.
Meta
- ui.Editbox.filename r
-
The filename associated with the buffer.
Returns nil if no filename is associated with the buffer (this could happen for example, when you call up the editor with
shift-F4
). - ui.Editbox.fullscreen rw
-
Whether the editbox is shown fullscreen.
An editbox normally fills the whole client area of the editor (“fullscreen”), but it may alternatively be shown inside a resizeable framed box within.
Example:
-- Make the current editbox occupy the western half of the screen. ui.Editbox.bind("C-l w", function(edt) -- (1) Show it in its own box: edt.fullscreen = false -- (2) Set the dimensions to be half of the editor's ("the editor" -- simply being the dialog; but we can instead just use -- tty.get_cols() and tty.get_rows()). -- -- Note that doing 'edt.fullscreen = false' restores the editbox' -- dimensions to previously recorded ones, so we have to set the -- dimensions _afterwards_ or they'll get overwritten. -- edt.x, edt.y = 0, 1 edt.cols = math.ceil(edt.dialog.cols / 2) edt.rows = edt.dialog.rows - 2 -- (3) We need to redraw the entire dialog because some areas in -- it now contain junk (where the editbox has been). tty.redraw() -- We can do 'edt.dialog:redraw()' too. end)
- ui.Editbox:get_markers()
-
Returns the extents of the selected text.
When text is selected (aka “marked”) within the buffer, it is identified by its starting marker and ending marker. “Marker” being an offset, in bytes, within the buffer.
This function returns the two markers. If no text is selected, nothing is returned.
It so happens that you can pass the two returned values directly to sub, which is why an
Editbox:get_selection()
method isn’t necessary:-- Show the marked text if edt:get_markers() then alert(edt:sub(edt:get_markers())) -- To be proper, we should use :to_tty before sending the text to alert(). end
- ui.Editbox:len()
-
Returns the size of the buffer.
That is, returns the number of bytes that compose the text.
- ui.Editbox.max_line r
- The number of lines in the buffer.
- ui.Editbox.modified rw
- Whether the buffer has been modified.
- ui.Editbox.top_line rw
- The number of the first line displayed.
Bookmarks
A bookmark has a UI style (color, underline, etc.) that tells MC how to display it.
A single line may hold several bookmarks.
- ui.Editbox:bookmark_clear(line, style)
-
Clears a bookmark.
Parameters:
- line Line number.
- style
The style whose bookmark is to be cleared, or
-1
to clear all bookmarks on this line.
- ui.Editbox:bookmark_exists(line, style)
-
Queries for a bookmark.
Parameters:
- line Line number.
- style
The style whose bookmark is to be looked for, or
-1
to look for any bookmark.
- ui.Editbox:bookmark_flush([style])
-
Clears all bookmarks.
Parameters:
- style
The style whose bookmarks are to be flushed. If omitted,
or if
-1
, all styles are flushed. (optional)
- style
The style whose bookmarks are to be flushed. If omitted,
or if
- ui.Editbox:bookmark_set(line, style)
-
Sets a bookmark.
-- Highlight lines 2 and 5 to show that we've found some -- string there. local found = tty.style("yellow, green") edt:bookmark_set(2, found) edt:bookmark_set(5, found) -- Highlight line 3 to show that it has a typo. local typo = tty.style("yellow, green") edt:bookmark_set(3, typo)
(See another example at lines.)
The above code reveals a subtle issue: bookmarks have only a UI style, not an ID. We can’t later tell the editor to clear all the “typo” bookmarks but leave the others, because they're indistinguishable from the “found” bookmarks: the found and typo variables happen to hold exactly the same value in our case (they are one and the same UI style). Hopefully bookmarks will have an ID in future versions of MC.
Parameters:
- line Line number.
- style The style to use for this bookmark.
Cursor
- ui.Editbox.cursor_col rw
-
The cursor’s column.
This is where on the screen the cursor ends up. That is, the widths of TAB characters, wide Asian characters and non-spacing characters are taken in account.
See also cursor_xoffs.
- ui.Editbox.cursor_line rw
- The cursor’s line number.
- ui.Editbox.cursor_offs rw
-
The cursor’s offset within the buffer.
(Byte-based, not character-based.)
Example:
-- Jump to the next place where "Linux" appears in the text. ui.Editbox.bind("C-c", function(edt) local pos = edt:sub(1):find("Linux", edt.cursor_offs + 1) if pos then edt.cursor_offs = pos else tty.beep() end end)
(For a useful variation of this code snippet, see search_by_regex.lua.)
- ui.Editbox.cursor_xoffs rw
-
The cursor’s offset within the line.
(Byte-based, not character-based.)
See also cursor_col.
Syntax
- ui.Editbox:add_keyword(s, style[, opts])
-
Syntax-highlights a string.
This adds a string (typically a keyword) to the syntax definition. This makes the string shown in a different style than normal text.
Example:
-- When you're editing source code you sometimes wish to see -- all the places on the screen where a variable is used. -- -- In Vim this is done with the * (asterisk) key. Here we use -- alt-* instead. -- ui.Editbox.bind('M-*', function(edt) abortive(edt.current_word, T'Stand on a word, will you?') edt:add_keyword(edt.current_word, tty.style('white, red'), {range='all'}) edt:redraw() end)
Another example:
-- Spellcheck the file. -- Misspelled words will be highlighted. ui.Editbox.bind('C-c', function(edt) local f = io.popen('spell < ' .. edt.filename .. ' | sort | uniq') for word in f:lines() do edt:add_keyword(word, tty.style('white, red'), {range='spellcheck'}) end edt:redraw() f:close() end)
(For better spellchecking, see editbox/speller.lua.)
Another example:
--[[ When you read novels you sometimes want people's names highlighted. Look no further :-) With this script you can add "Actors:" lines to the first lines of your novel's text to make that happen. Example: Actors: Benedict Brand Corwin Eric Julian Oberon (male) Actors: Deirdre Fiona Flora Llewella (female) It's probably convenient to use this on 256 color terminals only, where we can pick non-intrusive colors. ]] ui.Editbox.bind('<<load>>', function(edt) local styles = { -- By specifying only the foreground color we get the default -- background color, which is usually (not always) the editor's -- background as well. You may, of course, explicitly specify -- the background here. male = tty.style {color='yellow', hicolor='color159'}, -- Bluish female = tty.style {color='brown', hicolor='color219'}, -- Pinkish object = tty.style {color='white', hicolor='color186'}, -- Yellowish place = tty.style {color='green', hicolor='color120'}, -- Greenish } for line, i in edt:lines() do -- The following "[o]" is a trick to prevent this line from -- being recognized as an Actors line. local names, gender = line:match "Act[o]rs:(.*)%((.*)%)" if names then for name in names:gmatch "[^%s,]+" do edt:add_keyword(name, abortive(styles[gender], 'missing style ' .. gender), {range='all'}) end end if i > 50 then -- look in 50 first lines only. break end end end)
Parameters:
- s The string to highlight.
- style The style to highlight it in.
- opts
An optional table with additional options:
whole (true by default): Whether the string must be whole (bounded by non-word characters) or not.
range (“default” by default): One of “default”, “all”, “spellcheck”, “!spellcheck”. Syntaxes are composed of contexts; E.g., in a programming language the default context holds normal code, another context is for comments, another for strings, etc. The range option determines which context(s) the string will be added to. By default the string will be added to the default context only (which means that it won’t be recognized in comments and strings). You can specify “all” to add it to all contexts; “spellcheck” to add it to all contexts marked as being appropriate for spell checking; and “!spellcheck” for those not marked so.
linestart (false by default): Whether the string must start at beginnings of lines.
- ui.Editbox:get_style_at(pos)
-
Returns the style at a certain position.
See usage example at tty.destruct_style.
Parameters:
- pos Position in buffer (1-based; byte-oriented).
- ui.Editbox.syntax rw
-
The buffer’s syntax type.
E.g., “C Program”, “HTML File”, “Shell Script”. If no syntax is associated with the buffer, this property is nil.
Examples:
-- Treat "README" files as HTML files. ui.Editbox.bind('<<load>>', function(edt) if edt.filename and edt.filename:find 'README' then edt.syntax = "HTML File" end end) -- Auto-detect HTML files. -- It looks for a closing HTML tag in the first 1024 bytes. ui.Editbox.bind('<<load>>', function(edt) if not edt.syntax then if edt:sub(1,1024):find '</' then edt.syntax = "HTML File" end end end)
i18n
- ui.Editbox:is_utf8()
- Whether the buffer is UTF-8 encoded.
- ui.Editbox:to_tty(s)
-
Converts a string, extracted from the buffer, to the terminal’s encoding.
See example and discussion at Encodings.
Static functions
- ui.Editbox.options
-
Editor options.
A table containing some editbox options, which you can get and set.
-- Show line numbers when editing C files. ui.Editbox.bind("<<load>>", function(edt) if edt.syntax == "C Program" then ui.Editbox.options.show_numbers = true else ui.Editbox.options.show_numbers = false end end)
Note that these are global options. Unfortunately, MC doesn’t store these values on each Editbox but in shared global variables. This means that you can’t have two Editboxes opened at once each having a different
tab_size
value.Here are the available fields (options). In parentheses is how the feature is named in MC’s Editor Options dialog.
- tab_size – The tab character width
- fake_half_tab – (boolean) Simulate tabs at half the size.
- expand_tab – (boolean) Emit spaces, instead of a tab, when the TAB key is pressed.
- show_tabs – (boolean) Show tabs (“Visible tabs”).
- show_tws – (boolean) Show trailing whitespace (“Visible trailing spaces”).
- show_numbers – (boolean) Show line numbers.
- wrap_column – The column for word-wrapping.
- show_right_margin – (boolean) Show where wrap_column is (works even if wrapping is off). A useful feature found in many other editors.
- save_position – (boolean) Save the file position when the editbox is closed.
Static functions (syntax)
- ui.Editbox.get_syntax_list()
-
Returns a list of all the recognized syntaxes.
keymap.bind('C-y', function() devel.view { "Supported syntaxes:", ui.Editbox.syntax_list } end)
- ui.Editbox.search_syntax(keyword)
-
Searches within the syntax list.
As mentioned earlier, the syntax property is a human-readable pretty string instead of being a keyword. This utility function tries its best to find a syntax string that matches a keyword.
assert(ui.Editbox.search_syntax("bison") == "Yacc/Bison Parser") assert(ui.Editbox.search_syntax("PERL") == "Perl Program") assert(ui.Editbox.search_syntax("C#") == "C# Program")
It returns nil if it finds none.
Events
- <<load>>
-
Triggered when an editbox is opened.
Example:
ui.Editbox.bind("<<load>>", function(edt) alert(edt.syntax) end)
Another example:
-- When a user opens a *.log file, automatically jump to its -- end and insert a date header. ui.Editbox.bind('<<load>>', function(edt) if edt.filename and edt.filename:find '%.log$' then edt.cursor_offs = edt:len() + 1 edt:insert("\n--------" .. os.date() .. "--------\n") end end)
See more examples at ui.Editbox:add_keyword, ui.Editbox.syntax, ui.Editbox.options, modeline.lua.
- <<unload>>
- Triggered when an editbox is closed.