2880 lines
86 KiB
Plaintext
2880 lines
86 KiB
Plaintext
|
-- Wee Euphoria Editor
|
||
|
--
|
||
|
-- Copyright (c) 1998-2016 Pete Eberlein
|
||
|
--
|
||
|
-- Permission is hereby granted, free of charge, to any person obtaining a copy
|
||
|
-- of this software and associated documentation files (the "Software"), to deal
|
||
|
-- in the Software without restriction, including without limitation the rights
|
||
|
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||
|
-- copies of the Software, and to permit persons to whom the Software is
|
||
|
-- furnished to do so, subject to the following conditions:
|
||
|
--
|
||
|
-- The above copyright notice and this permission notice shall be included in
|
||
|
-- all copies or substantial portions of the Software.
|
||
|
--
|
||
|
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
|
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
|
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||
|
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||
|
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||
|
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||
|
-- THE SOFTWARE.
|
||
|
|
||
|
global constant
|
||
|
window_title = "Wee Euphoria Editor",
|
||
|
author = "Pete Eberlein <pete.eberlein@gmail.com>",
|
||
|
version = "0.48",
|
||
|
changelog = `
|
||
|
|
||
|
Version 0.48
|
||
|
- Bug fix: hang during replace all (thanks Andreas)
|
||
|
- Auto-detect EOL characters when opening
|
||
|
|
||
|
Version 0.47
|
||
|
- Bug fix: parser support for "loop until" statement (thanks dcuny)
|
||
|
|
||
|
Version 0.46
|
||
|
- Bug fix: parser should allow case statements inside ifdef
|
||
|
- Bug fix: crash in parser for non-existent namespace include (thanks Andreas)
|
||
|
|
||
|
Version 0.45
|
||
|
- Help->Release Notes to view changelog
|
||
|
- Bug fix: use EUDIR when locating help index
|
||
|
- Bug fix: 'not' in ifdefs was flagged as an error
|
||
|
- Bug fix: set default indentation for new tabs
|
||
|
- Bug fix: clear insert chars after auto-indent
|
||
|
|
||
|
Version 0.44
|
||
|
- ARM scintilla library (tested on Raspberry Pi 2)
|
||
|
|
||
|
Version 0.43
|
||
|
- Bug fixed: open shell in current directory (UNIX)
|
||
|
|
||
|
Version 0.42
|
||
|
- Run commands in a temporary script (Linux/OSX)
|
||
|
|
||
|
Version 0.41
|
||
|
- Improved parsing speed
|
||
|
|
||
|
Version 0.40
|
||
|
- Bug fixed: crashes on auto-completion and error parsing (thanks dcuny)
|
||
|
|
||
|
Version 0.39
|
||
|
- Error indicators and mouse dwell message
|
||
|
- Add namespaces to auto-complete (with 'n' icon)
|
||
|
- Add EUDIR support
|
||
|
- Bug fixed: mousewheel tab change on Windows
|
||
|
|
||
|
Version 0.38
|
||
|
- Adding run options: background and test run (thanks KDR)
|
||
|
- Bug fixed: crash on fail to open file during parsing (thanks sdpringle)
|
||
|
- Bug fixed: crash on error while saving (thanks sdpringle)
|
||
|
|
||
|
Version 0.37
|
||
|
- Filename first in window title
|
||
|
- Tabs now have mouseover tooltip with full path (win32: only the active tab)
|
||
|
- Bug fixed: crash when interpreter list is empty (thanks Irv)
|
||
|
|
||
|
Version 0.36
|
||
|
- Windows icon built-in
|
||
|
- Run Set Interpreter now lets you override the interpreter used
|
||
|
|
||
|
Version 0.35
|
||
|
- Allow quoted include filename (thanks dcuny)
|
||
|
|
||
|
Version 0.34
|
||
|
- Bug fix: crash on parsing "-type ..." (thanks dcuny)
|
||
|
|
||
|
Version 0.33
|
||
|
- select next/prev tab using mouse wheel over tabs
|
||
|
- close tab with middle mouse button
|
||
|
- select next tab (Ctrl+Tab) and previous tab (Shift+Ctrl+Tab)
|
||
|
|
||
|
Version 0.32
|
||
|
- 64-bit supported on Windows (joining Linux/OSX)
|
||
|
- Bug fix: no message when opening saved tab whose file no longer exists
|
||
|
|
||
|
Version 0.31
|
||
|
- Bug fix: cursor color changes based on background (thanks Andreas)
|
||
|
- Bug fix: string color not loaded from config file (thanks Andreas)
|
||
|
- Bug fix: bold options reversed for String and Number
|
||
|
- Bug fix: incorrect tab or new tab selected when reopening tabs
|
||
|
|
||
|
Version 0.30
|
||
|
- Options to disable auto-completing statements or braces
|
||
|
- Auto-completion and syntax coloring disabled for non-Euphoria files
|
||
|
- Bold options for syntax coloring
|
||
|
- Bug fix: crash when typing character literals with calltip active
|
||
|
- Bug fix: GTK version: close tab didn't prompt to save modified files
|
||
|
|
||
|
Version 0.29
|
||
|
- Bug fix: crash + lose wee_conf when closing on Windows with reopen_tabs=1
|
||
|
|
||
|
Version 0.28
|
||
|
- Run menu choose which intepreter to use
|
||
|
- Run will choose interpreter location (based on eu.cfg include path)
|
||
|
- Option to reopen tabs next time
|
||
|
|
||
|
Version 0.27
|
||
|
- autocompletion list shows icons for each type of declaration
|
||
|
|
||
|
Version 0.26
|
||
|
- line wrap option
|
||
|
- Bug fix: preserve selection during comment/uncomment lines
|
||
|
|
||
|
Version 0.25
|
||
|
- fill in Find dialog with current selection
|
||
|
- allow search backward in Find and Replace dialogs
|
||
|
- quick search Find Next (Ctrl+G) Find Previous (Shift+Ctrl+G)
|
||
|
- comment/uncomment selected lines (Ctrl+M)
|
||
|
- go back (Esc) after doing View Declaration or Goto Error
|
||
|
- if there is a selection, it will be deselected first
|
||
|
|
||
|
Version 0.24
|
||
|
- drag'n'drop files
|
||
|
|
||
|
Version 0.23
|
||
|
- Bug fix: run/bind/shroud/translate didn't like spaces in the path
|
||
|
|
||
|
Version 0.22
|
||
|
- Bug fix: better at locating scintilla library when bound/compiled
|
||
|
|
||
|
Version 0.21
|
||
|
- dialog to change syntax highlighting colors
|
||
|
- popup menu on tab control
|
||
|
|
||
|
Version 0.20
|
||
|
- run with arguments (Shift+F5)
|
||
|
- move options to separate menu
|
||
|
- option to sort subroutines in View Subroutines dialog
|
||
|
- added Bind, Shroud and Translate to Run menu
|
||
|
|
||
|
Version 0.19
|
||
|
- Linux/Mac (using EuGTK)
|
||
|
- context-sensitive help (hit F1 on a word)
|
||
|
|
||
|
Version 0.18
|
||
|
- store syntax highlighting colors in wee.conf
|
||
|
|
||
|
Version 0.17
|
||
|
- updated: indent/unindent selection with tab/shift-tab
|
||
|
|
||
|
Version 0.16
|
||
|
- updated: ex.err dialog with buttons: <cancel> <open ex.err> <goto error>
|
||
|
- and listbox with call stack or multiple undeclared references
|
||
|
- Bug fix: weirdness with deletion autoinserted closing characters
|
||
|
- Bug fix: calltip popup displaying incorrect highlight after first time
|
||
|
- Bug fix: EOL mode on Linux/OSX
|
||
|
- Bug fix: completions are now sorted
|
||
|
- Bug fix: switch/case syntax highlight and autocomplete were missing
|
||
|
- Bug fix: shift-ctrl-Z does redo
|
||
|
|
||
|
Version 0.15
|
||
|
- hardcoded list of builtins and arguments in get_subroutine_arguents()
|
||
|
|
||
|
Version 0.13
|
||
|
- auto-complete with include puts it near top of file
|
||
|
- auto insert closing characters for ( { [ " '
|
||
|
- typing '(' after a subroutine will popup hints
|
||
|
- Bug fix: autocomplete avoids activating inside comments and strings
|
||
|
|
||
|
Version 0.12
|
||
|
- auto expansions for "if" "while" "for" and subroutines (thanks dcuny)
|
||
|
- auto indent newlines
|
||
|
- type ':' to autocomplete a namespace
|
||
|
|
||
|
Version 0.11
|
||
|
- view completions will search std includes
|
||
|
- Search->Find will remember last phrase
|
||
|
- fixed tab names not updating when save-as
|
||
|
- fixed "too many open files" error, wasn't closing files in view_error function
|
||
|
- fixed parsing ifdefs
|
||
|
- fixed crash after changing font (thanks euphoric)
|
||
|
- reloading a file that is modified externally loads into wrong tab (thanks dcuny)
|
||
|
|
||
|
Version 0.10
|
||
|
- Bug fix: ViewCompletions on whitespace crash
|
||
|
|
||
|
Version 0.09
|
||
|
- Scintilla edit control (using Lua lexer :/)
|
||
|
|
||
|
Version 0.08
|
||
|
- watch tabs for changes to files and ex.err
|
||
|
- goto declaration (Ctrl+F2) and view completions (Ctrl+Space)
|
||
|
|
||
|
Version 0.07
|
||
|
- tabs (can be selected using Alt+1..9)
|
||
|
|
||
|
Older Versions
|
||
|
- syntax coloring!
|
||
|
- Bug fix: save mode changed to "wb" (Thanks Lucius)
|
||
|
- replace all
|
||
|
- goto error
|
||
|
- hotkeys
|
||
|
- cursor position
|
||
|
- recent files list
|
||
|
- saving window pos+size and recent files to "wee_conf.txt"
|
||
|
- subroutines list dialog (F2)
|
||
|
- choose font dialog (we suggest "Consolas" 11pt)
|
||
|
|
||
|
- bugs fixed:
|
||
|
- ViewDeclaration wrong cursor pos
|
||
|
- audible ding when pressing Alt+1..9
|
||
|
- parser updates cache for modified include files
|
||
|
- files are now opened in binary mode since scintilla can handle any line endings
|
||
|
`
|
||
|
|
||
|
-- todo:
|
||
|
-- bug with reloading files, first few characters get garbled
|
||
|
-- expanding "for" should then tab between "=", "to", and "do"
|
||
|
-- as it is now, its really annoying (but better with overtyping)
|
||
|
-- fix brace highlighting in comments and strings
|
||
|
-- put arguments after each subroutine completion (maybe)
|
||
|
-- investigate Mike Duffy's scintilla Euphoria Lexer
|
||
|
-- multicolored brackets and parens
|
||
|
-- multiline comments and strings
|
||
|
-- code-aware identifier rename
|
||
|
-- add function to parser to get all instances of identifier in scope
|
||
|
-- use multi-select to replace all instances in one shot
|
||
|
-- limited to a single file (too difficult otherwise)
|
||
|
-- macro recording (SCI_STARTRECORD/SCI_STOPRECORD/SCN_MACRORECORD)
|
||
|
-- disable menu items when the action has no effect
|
||
|
-- disable cut/copy when no selection, or paste with empty clipboard
|
||
|
-- disable undo/redo when nothing to do
|
||
|
-- disable go back when nowhere to go back to
|
||
|
-- old calltips sometimes pop up after a calltip elsewhere is closed
|
||
|
-- probably due to nesting calltips
|
||
|
-- will crash by putting a function after sci_notify() (Linux/OSX 64-bit)
|
||
|
-- triggered by using Alt+1-9 to change tabs
|
||
|
-- Euphoria bug? file a ticket
|
||
|
-- help->check for updates
|
||
|
-- updating dll would require updater.ex
|
||
|
-- option to bind/shround/recompile
|
||
|
-- edit->tidy, to clean up indentation/formatting
|
||
|
|
||
|
--without warning
|
||
|
|
||
|
include parser.e
|
||
|
include scintilla.e
|
||
|
include std/get.e
|
||
|
include std/filesys.e
|
||
|
include std/sequence.e
|
||
|
include std/text.e
|
||
|
include std/machine.e
|
||
|
include std/error.e
|
||
|
include std/io.e
|
||
|
include weeicon.e
|
||
|
|
||
|
-- The ui includes are circular includes:
|
||
|
-- wee.exw -> ui_win.e -> wee.exw
|
||
|
-- The ui include is responsible for calling wee_init() and startup.
|
||
|
ifdef WINDOWS then
|
||
|
include ui_win.e
|
||
|
elsedef
|
||
|
include ui_gtk.e
|
||
|
end ifdef
|
||
|
|
||
|
-- all variables must be initialized in wee_init() due to circular include
|
||
|
global constant max_recent_files = 5
|
||
|
|
||
|
|
||
|
-- these are configuration settings saved to wee_conf
|
||
|
global atom x_pos, y_pos, x_size, y_size
|
||
|
global sequence font_name, recent_files,
|
||
|
terminal_program -- for GTK, runs programs in a terminal
|
||
|
global integer font_height,
|
||
|
line_numbers, -- boolean
|
||
|
sorted_subs, -- boolean
|
||
|
line_wrap, -- boolean
|
||
|
reopen_tabs, -- boolean
|
||
|
tab_width, -- usually 8
|
||
|
indentation_guides, -- boolean
|
||
|
caret_width, -- in pixels
|
||
|
complete_statements, -- when typing "if " -> "if | then\n \nend if"
|
||
|
complete_braces, -- when typing '(' or '[' or '{' or ''' or '"'
|
||
|
auto_namespace, -- when typing ':'
|
||
|
auto_complete, -- when typing two word chars or backspace
|
||
|
auto_arguments, -- when typing '(' after an identifier
|
||
|
auto_indent, -- when creating a new line
|
||
|
auto_indicator, -- underline words that are not in scope
|
||
|
run_testrun, -- run exe after bind/shroud/translate
|
||
|
run_background, -- for GTK, run programs/terminal in background
|
||
|
run_waitkey, -- wait for keypress after running in a terminal
|
||
|
keyword_color, builtin_color, string_color,
|
||
|
comment_color, number_color, normal_color, background_color,
|
||
|
linenumber_color, bracelight_color, bold_flags
|
||
|
sequence tabs_to_open -- {{"filename", pos, topline},...}
|
||
|
sequence file_types -- {{{"ext1","ext2",...}, SCLEX_x, {index, "keywords ...", ...}, {"match", "expand",...}
|
||
|
|
||
|
|
||
|
global sequence file_name, run_file_name, ex_err_name
|
||
|
global sequence find_phrase, replace_phrase, interpreter, wee_path
|
||
|
|
||
|
|
||
|
-- local variables
|
||
|
sequence
|
||
|
tab_hedits, tab_file_names, tab_timestamps,
|
||
|
recent_pos, tab_arguments, tab_pos_stack
|
||
|
integer current_tab, modified, initial_tab
|
||
|
atom hedit
|
||
|
atom ex_err_timestamp
|
||
|
integer expand_line, last_deleted_char
|
||
|
sequence insert_chars
|
||
|
sequence calltip_args -- {{start,end},...}
|
||
|
integer calltip_pos
|
||
|
sequence calltip_stack -- {calltip_pos, calltip_args...}
|
||
|
sequence calltip_text -- "routine_name(type1 arg1, ...)"
|
||
|
integer calltip_dwell -- flag indicating calltip from mouse dwell
|
||
|
sequence wee_conf_filename
|
||
|
sequence search_idx, search_dat
|
||
|
sequence expansions
|
||
|
sequence last_errors
|
||
|
atom change_time -- when to perform error indicator checking
|
||
|
|
||
|
-- shorthand helper function
|
||
|
function ssm(integer m, object w=0, object l=0)
|
||
|
return scintilla_send_message(hedit, m, w, l)
|
||
|
end function
|
||
|
|
||
|
|
||
|
function crash_cleanup(object x)
|
||
|
ui_message_box_error(window_title,
|
||
|
"Houston, Wee've had a problem.\n\n" &
|
||
|
"The editor crashed and is closing now.\n")
|
||
|
save_modified_tabs()
|
||
|
if length(wee_conf_filename) then
|
||
|
save_wee_conf(wee_conf_filename)
|
||
|
end if
|
||
|
return 0
|
||
|
end function
|
||
|
|
||
|
|
||
|
|
||
|
constant -- colors of various syntax classes
|
||
|
Black = #000000,
|
||
|
Gray = #AAAAAA,
|
||
|
DGray = #808080,
|
||
|
Green = #00AA00,
|
||
|
Yellow = #88FFFF,
|
||
|
Magenta = #AA00AA,
|
||
|
Cyan = #AAAA00,
|
||
|
Red = #0000AA,
|
||
|
Blue = #AA0000,
|
||
|
LightBlue = #FFFFDD,
|
||
|
White = #FFFFFF,
|
||
|
BrightRed = #0000FF
|
||
|
|
||
|
global procedure wee_init()
|
||
|
sequence cmdline
|
||
|
|
||
|
wee_conf_filename = ""
|
||
|
|
||
|
crash_routine(routine_id("crash_cleanup"))
|
||
|
|
||
|
recent_files = {}
|
||
|
recent_pos = {}
|
||
|
|
||
|
font_name = ""
|
||
|
font_height = 10
|
||
|
line_numbers = 0
|
||
|
sorted_subs = 0
|
||
|
line_wrap = 0
|
||
|
|
||
|
file_name = ""
|
||
|
hedit = 0
|
||
|
|
||
|
run_file_name = ""
|
||
|
ex_err_name = "ex.err"
|
||
|
ex_err_timestamp = get_timestamp(ex_err_name)
|
||
|
interpreter = ""
|
||
|
|
||
|
tab_hedits = {}
|
||
|
tab_file_names = {}
|
||
|
tab_timestamps = {}
|
||
|
tab_arguments = {}
|
||
|
tab_pos_stack = {}
|
||
|
last_errors = {}
|
||
|
|
||
|
modified = 0
|
||
|
expand_line = -1
|
||
|
insert_chars = ""
|
||
|
last_deleted_char = 0
|
||
|
auto_namespace = 1
|
||
|
auto_complete = 1
|
||
|
complete_statements = 1
|
||
|
complete_braces = 1
|
||
|
auto_arguments = 1
|
||
|
auto_indent = 1
|
||
|
tab_width = 8
|
||
|
indentation_guides = 0
|
||
|
caret_width = 2
|
||
|
auto_indicator = 1
|
||
|
run_testrun = 0
|
||
|
run_background = 1
|
||
|
run_waitkey = 1
|
||
|
|
||
|
calltip_args = {}
|
||
|
calltip_pos = -1
|
||
|
calltip_stack = {}
|
||
|
calltip_text = ""
|
||
|
calltip_dwell = 0
|
||
|
|
||
|
current_tab = 0
|
||
|
|
||
|
normal_color = Black
|
||
|
background_color = White
|
||
|
comment_color = DGray
|
||
|
number_color = Black
|
||
|
keyword_color = Green
|
||
|
builtin_color = Magenta
|
||
|
string_color = Blue
|
||
|
bracelight_color = LightBlue
|
||
|
linenumber_color = DGray
|
||
|
bold_flags = #40
|
||
|
|
||
|
search_idx = {}
|
||
|
search_dat = {}
|
||
|
|
||
|
find_phrase = ""
|
||
|
replace_phrase = ""
|
||
|
terminal_program = ""
|
||
|
|
||
|
reopen_tabs = 1
|
||
|
tabs_to_open = {}
|
||
|
initial_tab = 1
|
||
|
|
||
|
cmdline = command_line()
|
||
|
wee_path = canonical_path(dirname(cmdline[2]))
|
||
|
if length(wee_path) and wee_path[$] = SLASH then
|
||
|
wee_path = wee_path[1..$-1]
|
||
|
end if
|
||
|
|
||
|
file_types = {
|
||
|
{
|
||
|
-- extensions
|
||
|
{"ex", "e", "exw", "ew", "exu", "eu"},
|
||
|
-- SCLEX_constant
|
||
|
SCLEX_LUA,
|
||
|
-- identifiers used with SCI_SETIDENTIFIERS
|
||
|
{0,
|
||
|
"procedure function type end and or xor not if then elsif else for to by do while "&
|
||
|
"global constant include with without return exit "&
|
||
|
-- OE4
|
||
|
"public export enum as namespace ifdef elsifdef elsedef "&
|
||
|
"label entry break continue loop until routine switch case fallthru",
|
||
|
1,
|
||
|
get_builtins()
|
||
|
},
|
||
|
-- expansions used with auto_expand()
|
||
|
{{"if", "", " then", "end if"},
|
||
|
{"elsif", "", " then"},
|
||
|
{"while", "", " do", "end while"},
|
||
|
{"for", " = to ", " do", "end for"},
|
||
|
{"case", "", " then"},
|
||
|
{"loop", "", "do", "end loop"},
|
||
|
{"switch", "", " do", "end switch"},
|
||
|
{0, "global ", "public ", "export "},
|
||
|
{"procedure", "()", "", "end procedure"},
|
||
|
{"function", "()", "", "end function"},
|
||
|
{"type", "()", "", "end type"}
|
||
|
},
|
||
|
interpreter
|
||
|
},
|
||
|
{
|
||
|
-- extensions
|
||
|
{"c", "h", "cpp", "hpp"},
|
||
|
-- SCLEX_constant
|
||
|
SCLEX_CPP,
|
||
|
-- identifiers used with SCI_SETKEYWORDS
|
||
|
{0,
|
||
|
"if else for do while switch case default "&
|
||
|
"return break continue "&
|
||
|
"enum typedef struct union static const ",
|
||
|
1,
|
||
|
"void int char unsigned long sizeof"
|
||
|
},
|
||
|
-- expansions used with auto_expand()
|
||
|
{{"if", "()", " {", "}"},
|
||
|
{"} else if", "()", " { "},
|
||
|
{"while", "()", " {", "}"},
|
||
|
{"for", "(;;)", " {", "}"},
|
||
|
{"switch", "()", " {", "}"},
|
||
|
{"case", "", ":", "break;"}
|
||
|
}
|
||
|
},
|
||
|
{
|
||
|
-- extensions
|
||
|
{"htm", "html"},
|
||
|
-- SCLEX_constant
|
||
|
SCLEX_HTML,
|
||
|
-- identifiers used with SCI_SETKEYWORDS
|
||
|
{},
|
||
|
-- expansions used with auto_expand()
|
||
|
{}
|
||
|
}
|
||
|
}
|
||
|
expansions = {}
|
||
|
end procedure
|
||
|
|
||
|
|
||
|
|
||
|
global procedure load_wee_conf(sequence wee_conf_file)
|
||
|
integer f, eq, int_ok
|
||
|
object l
|
||
|
sequence key, val
|
||
|
f = open(wee_conf_file, "r")
|
||
|
if f = -1 then return end if
|
||
|
wee_conf_filename = wee_conf_file
|
||
|
l = gets(f)
|
||
|
while sequence(l) do
|
||
|
eq = find('=', l)
|
||
|
if eq then
|
||
|
key = l[1..eq-1]
|
||
|
val = l[eq+1..length(l)-1]
|
||
|
l = value(val)
|
||
|
int_ok = (l[1] = 0 and integer(l[2]))
|
||
|
if equal(key, "x_pos") and int_ok then
|
||
|
x_pos = l[2]
|
||
|
elsif equal(key, "y_pos") and int_ok then
|
||
|
y_pos = l[2]
|
||
|
elsif equal(key, "x_size") and int_ok then
|
||
|
x_size = l[2]
|
||
|
elsif equal(key, "y_size") and int_ok then
|
||
|
y_size = l[2]
|
||
|
elsif equal(key, "recent_file") then
|
||
|
recent_files &= {val}
|
||
|
elsif equal(key, "recent_pos") and int_ok then
|
||
|
recent_pos &= l[2]
|
||
|
elsif equal(key, "font_name") then
|
||
|
font_name = val
|
||
|
elsif equal(key, "font_height") and int_ok then
|
||
|
font_height = l[2]
|
||
|
if font_height < 0 then
|
||
|
font_height = -floor((font_height*96+36)/72)
|
||
|
end if
|
||
|
elsif equal(key, "line_numbers") and int_ok then
|
||
|
line_numbers = l[2]
|
||
|
elsif equal(key, "normal_color") and int_ok then
|
||
|
normal_color = l[2]
|
||
|
elsif equal(key, "background_color") and int_ok then
|
||
|
background_color = l[2]
|
||
|
elsif equal(key, "comment_color") and int_ok then
|
||
|
comment_color = l[2]
|
||
|
elsif equal(key, "keyword_color") and int_ok then
|
||
|
keyword_color = l[2]
|
||
|
elsif equal(key, "builtin_color") and int_ok then
|
||
|
builtin_color = l[2]
|
||
|
elsif equal(key, "number_color") and int_ok then
|
||
|
number_color = l[2]
|
||
|
elsif equal(key, "string_color") and int_ok then
|
||
|
string_color = l[2]
|
||
|
elsif equal(key, "linenumber_color") and int_ok then
|
||
|
linenumber_color = l[2]
|
||
|
elsif equal(key, "bracelight_color") and int_ok then
|
||
|
bracelight_color = l[2]
|
||
|
elsif equal(key, "sorted_subs") and int_ok then
|
||
|
sorted_subs = l[2]
|
||
|
elsif equal(key, "line_wrap") and int_ok then
|
||
|
line_wrap = l[2]
|
||
|
elsif equal(key, "interpreter") then
|
||
|
if not find(val, {"eui","euiw","ex","exw"}) then
|
||
|
interpreter = val
|
||
|
end if
|
||
|
elsif equal(key, "reopen_tabs") and int_ok then
|
||
|
reopen_tabs = l[2]
|
||
|
elsif equal(key, "open_tab") then
|
||
|
if length(l[2]) = 3 and sequence(l[2][1]) and integer(l[2][2]) and integer(l[2][3]) then
|
||
|
tabs_to_open = append(tabs_to_open, l[2])
|
||
|
else
|
||
|
tabs_to_open = append(tabs_to_open, {val, 0, 0})
|
||
|
end if
|
||
|
elsif equal(key, "open_tab_pos") and int_ok then
|
||
|
tabs_to_open[$][2] = l[2]
|
||
|
elsif equal(key, "open_tab_line") and int_ok then
|
||
|
tabs_to_open[$][3] = l[2]
|
||
|
elsif equal(key, "initial_tab") and int_ok then
|
||
|
initial_tab = l[2]
|
||
|
elsif equal(key, "complete_statements") and int_ok then
|
||
|
complete_statements = l[2]
|
||
|
elsif equal(key, "complete_braces") and int_ok then
|
||
|
complete_braces = l[2]
|
||
|
elsif equal(key, "bold_flags") and int_ok then
|
||
|
bold_flags = l[2]
|
||
|
elsif equal(key, "tab_width") and int_ok then
|
||
|
tab_width = l[2]
|
||
|
elsif equal(key, "indentation_guides") and int_ok then
|
||
|
indentation_guides = l[2]
|
||
|
elsif equal(key, "caret_width") and int_ok then
|
||
|
caret_width = l[2]
|
||
|
elsif equal(key, "terminal_program") then
|
||
|
terminal_program = val
|
||
|
elsif equal(key, "run_testrun") and int_ok then
|
||
|
run_testrun = l[2]
|
||
|
elsif equal(key, "run_background") and int_ok then
|
||
|
run_background = l[2]
|
||
|
elsif equal(key, "run_waitkey") and int_ok then
|
||
|
run_waitkey = l[2]
|
||
|
end if
|
||
|
end if
|
||
|
l = gets(f)
|
||
|
end while
|
||
|
close(f)
|
||
|
end procedure
|
||
|
|
||
|
global procedure save_wee_conf(sequence wee_conf_file)
|
||
|
integer f
|
||
|
f = open(wee_conf_file, "w")
|
||
|
printf(f, "x_pos=%d\ny_pos=%d\nx_size=%d\ny_size=%d\nline_numbers=%d\n",
|
||
|
{x_pos, y_pos, x_size, y_size, line_numbers})
|
||
|
for i = 1 to length(recent_files) do
|
||
|
puts(f, "recent_file="&recent_files[i]&"\n")
|
||
|
printf(f, "recent_pos=%d\n", {recent_pos[i]})
|
||
|
end for
|
||
|
if length(font_name) and font_height != 0 then
|
||
|
printf(f, "font_name=%s\nfont_height=%d\n", {font_name, font_height})
|
||
|
end if
|
||
|
printf(f, "normal_color=#%06x\n", {normal_color})
|
||
|
printf(f, "background_color=#%06x\n", {background_color})
|
||
|
printf(f, "keyword_color=#%06x\n", {keyword_color})
|
||
|
printf(f, "builtin_color=#%06x\n", {builtin_color})
|
||
|
printf(f, "comment_color=#%06x\n", {comment_color})
|
||
|
printf(f, "number_color=#%06x\n", {number_color})
|
||
|
printf(f, "string_color=#%06x\n", {string_color})
|
||
|
printf(f, "linenumber_color=#%06x\n", {linenumber_color})
|
||
|
printf(f, "bracelight_color=#%06x\n", {bracelight_color})
|
||
|
printf(f, "bold_flags=#%x\n", {bold_flags})
|
||
|
printf(f, "sorted_subs=%d\n", {sorted_subs})
|
||
|
printf(f, "line_wrap=%d\n", {line_wrap})
|
||
|
printf(f, "interpreter=%s\n", {interpreter})
|
||
|
printf(f, "reopen_tabs=%d\n", {reopen_tabs})
|
||
|
printf(f, "initial_tab=%d\n", {current_tab})
|
||
|
if reopen_tabs then
|
||
|
for i = 1 to length(tab_file_names) do
|
||
|
if length(tab_file_names[i]) then
|
||
|
hedit = tab_hedits[i]
|
||
|
printf(f, "open_tab=%s\nopen_tab_pos=%d\nopen_tab_line=%d\n", {
|
||
|
tab_file_names[i],
|
||
|
ssm(SCI_GETCURRENTPOS),
|
||
|
ssm(SCI_GETFIRSTVISIBLELINE)})
|
||
|
end if
|
||
|
end for
|
||
|
end if
|
||
|
printf(f, "complete_statements=%d\n", {complete_statements})
|
||
|
printf(f, "complete_braces=%d\n", {complete_braces})
|
||
|
printf(f, "tab_width=%d\n", {tab_width})
|
||
|
printf(f, "indentation_guides=%d\n", {indentation_guides})
|
||
|
printf(f, "caret_width=%d\n", {caret_width})
|
||
|
printf(f, "terminal_program=%s\n", {terminal_program})
|
||
|
printf(f, "run_testrun=%d\n", {run_testrun})
|
||
|
printf(f, "run_background=%d\n", {run_background})
|
||
|
printf(f, "run_waitkey=%d\n", {run_waitkey})
|
||
|
close(f)
|
||
|
end procedure
|
||
|
|
||
|
|
||
|
|
||
|
function sreplace(sequence text, sequence what, sequence replacement)
|
||
|
integer i
|
||
|
i = match(what, text)
|
||
|
if i then
|
||
|
return text[1..i-1] & replacement & text[i+length(what)..$]
|
||
|
end if
|
||
|
return text
|
||
|
end function
|
||
|
|
||
|
-- update the hedit lexer based on the file extension
|
||
|
procedure update_lexer()
|
||
|
sequence ext, keywords
|
||
|
integer lexer
|
||
|
|
||
|
if length(tab_file_names[current_tab]) then
|
||
|
ext = lower(fileext(tab_file_names[current_tab]))
|
||
|
else
|
||
|
ext = "ex" -- New file
|
||
|
end if
|
||
|
|
||
|
lexer = SCLEX_NULL
|
||
|
expansions = {}
|
||
|
keywords = {}
|
||
|
for i = 1 to length(file_types) do
|
||
|
if find(ext, file_types[i][1]) then
|
||
|
lexer = file_types[i][2]
|
||
|
keywords = file_types[i][3]
|
||
|
expansions = file_types[i][4]
|
||
|
exit
|
||
|
end if
|
||
|
end for
|
||
|
if lexer != ssm(SCI_GETLEXER) then
|
||
|
ssm(SCI_SETLEXER, lexer)
|
||
|
init_edit(hedit)
|
||
|
for k = 1 to length(keywords) by 2 do
|
||
|
ssm(SCI_SETKEYWORDS, keywords[k], keywords[k+1])
|
||
|
end for
|
||
|
end if
|
||
|
end procedure
|
||
|
|
||
|
|
||
|
-- init edit, (or reinit all existing edits when hedit = 0)
|
||
|
global procedure init_edit(atom edit)
|
||
|
sequence font
|
||
|
integer lexer
|
||
|
|
||
|
hedit = edit
|
||
|
|
||
|
font = font_name
|
||
|
ifdef not WINDOWS then
|
||
|
font = sreplace(font, "Medium", "")
|
||
|
font = sreplace(font, "Thin", "")
|
||
|
font = sreplace(font, "Bold", "")
|
||
|
font = sreplace(font, "Italic", "")
|
||
|
font = sreplace(font, "Condensed", "")
|
||
|
font = rtrim(font)
|
||
|
end ifdef
|
||
|
|
||
|
ssm(SCI_STYLESETFONT, STYLE_DEFAULT, font)
|
||
|
ifdef not WINDOWS then
|
||
|
ssm(SCI_STYLESETBOLD, STYLE_DEFAULT, match(" Bold", font_name))
|
||
|
ssm(SCI_STYLESETITALIC, STYLE_DEFAULT, match(" Italic", font_name))
|
||
|
end ifdef
|
||
|
ssm(SCI_STYLESETSIZE, STYLE_DEFAULT, font_height)
|
||
|
ssm(SCI_STYLESETFORE, STYLE_DEFAULT, normal_color)
|
||
|
ssm(SCI_STYLESETBACK, STYLE_DEFAULT, background_color)
|
||
|
ssm(SCI_SETCARETFORE, xor_bits(background_color, #FFFFFF))
|
||
|
ssm(SCI_STYLESETBOLD, STYLE_DEFAULT, and_bits(bold_flags, 1))
|
||
|
ssm(SCI_STYLECLEARALL)
|
||
|
|
||
|
lexer = ssm(SCI_GETLEXER)
|
||
|
|
||
|
if lexer = SCLEX_LUA then
|
||
|
ssm(SCI_STYLESETFORE, SCE_LUA_COMMENT, comment_color)
|
||
|
ssm(SCI_STYLESETBOLD, SCE_LUA_COMMENT, 0 != and_bits(bold_flags, 2))
|
||
|
ssm(SCI_STYLESETFORE, SCE_LUA_COMMENTLINE, comment_color)
|
||
|
ssm(SCI_STYLESETBOLD, SCE_LUA_COMMENTLINE, 0 != and_bits(bold_flags, 2))
|
||
|
ssm(SCI_STYLESETFORE, SCE_LUA_STRING, string_color)
|
||
|
ssm(SCI_STYLESETBOLD, SCE_LUA_STRING, 0 != and_bits(bold_flags, 4))
|
||
|
ssm(SCI_STYLESETFORE, SCE_LUA_WORD, keyword_color)
|
||
|
ssm(SCI_STYLESETBOLD, SCE_LUA_WORD, 0 != and_bits(bold_flags, 8))
|
||
|
ssm(SCI_STYLESETFORE, SCE_LUA_WORD2, builtin_color)
|
||
|
ssm(SCI_STYLESETBOLD, SCE_LUA_WORD2, 0 != and_bits(bold_flags, #10))
|
||
|
ssm(SCI_STYLESETFORE, SCE_LUA_NUMBER, number_color)
|
||
|
ssm(SCI_STYLESETBOLD, SCE_LUA_NUMBER, 0 != and_bits(bold_flags, #20))
|
||
|
elsif lexer = SCLEX_CPP then
|
||
|
ssm(SCI_STYLESETFORE, SCE_C_COMMENT, comment_color)
|
||
|
ssm(SCI_STYLESETBOLD, SCE_C_COMMENT, 0 != and_bits(bold_flags, 2))
|
||
|
ssm(SCI_STYLESETFORE, SCE_C_COMMENTLINE, comment_color)
|
||
|
ssm(SCI_STYLESETBOLD, SCE_C_COMMENTLINE, 0 != and_bits(bold_flags, 2))
|
||
|
ssm(SCI_STYLESETFORE, SCE_C_STRING, string_color)
|
||
|
ssm(SCI_STYLESETBOLD, SCE_C_STRING, 0 != and_bits(bold_flags, 4))
|
||
|
ssm(SCI_STYLESETFORE, SCE_C_WORD, keyword_color)
|
||
|
ssm(SCI_STYLESETBOLD, SCE_C_WORD, 0 != and_bits(bold_flags, 8))
|
||
|
ssm(SCI_STYLESETFORE, SCE_C_WORD2, builtin_color)
|
||
|
ssm(SCI_STYLESETBOLD, SCE_C_WORD2, 0 != and_bits(bold_flags, #10))
|
||
|
ssm(SCI_STYLESETFORE, SCE_C_NUMBER, number_color)
|
||
|
ssm(SCI_STYLESETBOLD, SCE_C_NUMBER, 0 != and_bits(bold_flags, #20))
|
||
|
end if
|
||
|
|
||
|
ssm(SCI_STYLESETBACK, STYLE_BRACELIGHT, bracelight_color)
|
||
|
ssm(SCI_STYLESETBOLD, STYLE_BRACELIGHT, 0 != and_bits(bold_flags, #40))
|
||
|
|
||
|
ssm(SCI_STYLESETFORE, STYLE_LINENUMBER, linenumber_color)
|
||
|
ssm(SCI_STYLESETBOLD, STYLE_LINENUMBER, 0 != and_bits(bold_flags, #80))
|
||
|
|
||
|
ssm(SCI_SETMARGINWIDTHN, 0, 48*line_numbers) -- line numbers margin visible
|
||
|
ssm(SCI_SETMARGINWIDTHN, 1, 0) -- non-folding symbols margin hidden
|
||
|
|
||
|
ssm(SCI_SETTABINDENTS, 1)
|
||
|
ssm(SCI_SETBACKSPACEUNINDENTS, 1)
|
||
|
ssm(SCI_SETINDENTATIONGUIDES, indentation_guides)
|
||
|
ssm(SCI_SETTABWIDTH, tab_width)
|
||
|
ssm(SCI_SETCARETWIDTH, caret_width)
|
||
|
|
||
|
ssm(SCI_AUTOCSETSEPARATOR, '\n')
|
||
|
ssm(SCI_AUTOCSTOPS, 0, " ")
|
||
|
ssm(SCI_AUTOCSETFILLUPS, 0, "")
|
||
|
--ssm(SCI_AUTOCSETORDER, SC_ORDER_CUSTOM) -- declaration order
|
||
|
ssm(SCI_AUTOCSETORDER, SC_ORDER_PERFORMSORT) -- scintilla should sort
|
||
|
ssm(SCI_AUTOCSETCANCELATSTART)
|
||
|
|
||
|
-- call tips display above text
|
||
|
ssm(SCI_CALLTIPSETPOSITION, 1)
|
||
|
|
||
|
-- get modification events for deletetext
|
||
|
ssm(SCI_SETMODEVENTMASK,
|
||
|
SC_MOD_INSERTTEXT +
|
||
|
SC_MOD_DELETETEXT +
|
||
|
SC_MOD_BEFOREDELETE)
|
||
|
|
||
|
ssm(SCI_SETWRAPMODE, line_wrap)
|
||
|
|
||
|
ifdef WINDOWS then
|
||
|
ssm(SCI_SETEOLMODE, SC_EOL_CRLF)
|
||
|
elsedef
|
||
|
ssm(SCI_SETEOLMODE, SC_EOL_LF)
|
||
|
end ifdef
|
||
|
|
||
|
ssm(SCI_REGISTERIMAGE, DECL_ATOM, a_xpm)
|
||
|
ssm(SCI_REGISTERIMAGE, DECL_CONSTANT, c_xpm)
|
||
|
ssm(SCI_REGISTERIMAGE, DECL_ENUM, e_xpm)
|
||
|
ssm(SCI_REGISTERIMAGE, DECL_FUNCTION, f_xpm)
|
||
|
ssm(SCI_REGISTERIMAGE, DECL_INTEGER, i_xpm)
|
||
|
ssm(SCI_REGISTERIMAGE, DECL_NAMESPACE, n_xpm)
|
||
|
ssm(SCI_REGISTERIMAGE, DECL_OBJECT, o_xpm)
|
||
|
ssm(SCI_REGISTERIMAGE, DECL_PROCEDURE, p_xpm)
|
||
|
ssm(SCI_REGISTERIMAGE, DECL_SEQUENCE, s_xpm)
|
||
|
ssm(SCI_REGISTERIMAGE, DECL_TYPE, t_xpm)
|
||
|
|
||
|
ssm(SCI_INDICSETSTYLE, 3, INDIC_SQUIGGLE)
|
||
|
ssm(SCI_INDICSETFORE, 3, BrightRed)
|
||
|
ssm(SCI_SETINDICATORCURRENT, 3)
|
||
|
ssm(SCI_SETMOUSEDWELLTIME, 500) -- milliseconds
|
||
|
|
||
|
end procedure
|
||
|
|
||
|
global procedure reinit_all_edits()
|
||
|
atom saved_hedit
|
||
|
saved_hedit = hedit
|
||
|
for i = 1 to length(tab_hedits) do
|
||
|
init_edit(tab_hedits[i])
|
||
|
end for
|
||
|
hedit = saved_hedit
|
||
|
end procedure
|
||
|
|
||
|
procedure auto_detect_indent(sequence text)
|
||
|
integer i = 0, indent = 0, last = 0, tabs_used = 0, spaces_used = 0
|
||
|
integer cr = 0, crlf = 0, lf = 0
|
||
|
sequence indents = repeat(0, 8)
|
||
|
|
||
|
while i < length(text) do
|
||
|
i += 1
|
||
|
-- count spaces and tabs
|
||
|
if text[i] = ' ' then
|
||
|
indent += 1
|
||
|
if remainder(indent, tab_width) = 0 then
|
||
|
spaces_used += 1
|
||
|
end if
|
||
|
continue
|
||
|
end if
|
||
|
if text[i] = '\t' then
|
||
|
indent += tab_width - remainder(indent, tab_width)
|
||
|
tabs_used += 1
|
||
|
continue
|
||
|
end if
|
||
|
|
||
|
-- record positive indents
|
||
|
if indent - last >= 1 and indent - last <= length(indents) then
|
||
|
indents[indent - last] += 1
|
||
|
end if
|
||
|
last = indent
|
||
|
indent = 0
|
||
|
|
||
|
-- scan to end of line and count eol styles
|
||
|
while i <= length(text) do
|
||
|
if text[i] = '\r' then -- cr
|
||
|
if i < length(text) and text[i+1] = '\n' then -- crlf
|
||
|
i += 1
|
||
|
crlf += 1
|
||
|
else
|
||
|
cr += 1
|
||
|
end if
|
||
|
exit
|
||
|
elsif text[i] = '\n' then -- lf
|
||
|
lf += 1
|
||
|
if i < length(text) and text[i+1] = '\r' then -- lfcr - not counted
|
||
|
i += 1
|
||
|
end if
|
||
|
exit
|
||
|
end if
|
||
|
i += 1
|
||
|
end while
|
||
|
|
||
|
end while
|
||
|
|
||
|
-- pick the max used indent size
|
||
|
indent = 1
|
||
|
for x = 2 to length(indents) do
|
||
|
if indents[x] > indents[indent] then
|
||
|
indent = x
|
||
|
end if
|
||
|
end for
|
||
|
|
||
|
ssm(SCI_SETINDENT, indent)
|
||
|
ssm(SCI_SETUSETABS, tabs_used > spaces_used)
|
||
|
|
||
|
-- pick the most used eol style
|
||
|
if cr > crlf and cr > lf then
|
||
|
ssm(SCI_SETEOLMODE, SC_EOL_CR)
|
||
|
elsif crlf > cr and crlf > lf then
|
||
|
ssm(SCI_SETEOLMODE, SC_EOL_CRLF)
|
||
|
elsif lf > cr and lf > crlf then
|
||
|
ssm(SCI_SETEOLMODE, SC_EOL_LF)
|
||
|
end if
|
||
|
|
||
|
end procedure
|
||
|
|
||
|
-- pos is integer position in current tab, or {"filename", pos}
|
||
|
-- note: first character in document is at pos=1
|
||
|
global procedure goto_pos(object pos, integer len=0)
|
||
|
sequence prev = {ssm(SCI_GETCURRENTPOS),
|
||
|
ssm(SCI_GETFIRSTVISIBLELINE)}
|
||
|
|
||
|
if sequence(pos) then
|
||
|
sequence prev_file = file_name
|
||
|
if open_file(pos[1], 0) = 0 then
|
||
|
return -- file not found
|
||
|
end if
|
||
|
pos = pos[2]
|
||
|
if not equal(file_name, prev_file) then
|
||
|
-- open_file probably changed the current_tab
|
||
|
prev &= {prev_file}
|
||
|
end if
|
||
|
end if
|
||
|
tab_pos_stack[current_tab] &= {prev}
|
||
|
pos -= 1
|
||
|
ssm(SCI_SETANCHOR, pos)
|
||
|
ssm(SCI_SETCURRENTPOS, pos + len)
|
||
|
set_top_line(-1)
|
||
|
end procedure
|
||
|
|
||
|
-- restore the previous cursor and scroll position,
|
||
|
-- or clear the selection or autocompletion if there is one
|
||
|
global procedure go_back()
|
||
|
object pos = ssm(SCI_GETCURRENTPOS)
|
||
|
|
||
|
-- clear any active autocomplete, and return
|
||
|
-- cancel any active call tip, and return
|
||
|
if ssm(SCI_AUTOCACTIVE) or ssm(SCI_CALLTIPACTIVE) then
|
||
|
ssm(SCI_AUTOCCANCEL)
|
||
|
ssm(SCI_CALLTIPCANCEL)
|
||
|
calltip_pos = -1
|
||
|
calltip_stack = {}
|
||
|
return
|
||
|
end if
|
||
|
|
||
|
-- clear any selection, and return
|
||
|
if pos != ssm(SCI_GETANCHOR) then
|
||
|
ssm(SCI_SETEMPTYSELECTION, pos)
|
||
|
return
|
||
|
end if
|
||
|
|
||
|
if length(tab_pos_stack[current_tab]) = 0 then
|
||
|
return -- empty stack
|
||
|
end if
|
||
|
|
||
|
-- get the last {pos,top_line,[filename]} on stack, and remove it
|
||
|
pos = tab_pos_stack[current_tab][$]
|
||
|
tab_pos_stack[current_tab] = tab_pos_stack[current_tab][1..$-1]
|
||
|
|
||
|
if sequence(pos) and length(pos) >= 3 then
|
||
|
if length(pos[3]) = 0 then
|
||
|
-- fixme: pick first untitled tab
|
||
|
integer tab = find("", tab_file_names)
|
||
|
if tab = 0 then
|
||
|
return
|
||
|
end if
|
||
|
select_tab(tab)
|
||
|
elsif open_file(pos[3], 0) = 0 then
|
||
|
return -- file not found or user cancelled
|
||
|
end if
|
||
|
end if
|
||
|
ssm(SCI_SETEMPTYSELECTION, pos[1])
|
||
|
set_top_line(pos[2])
|
||
|
end procedure
|
||
|
|
||
|
global function get_pos()
|
||
|
return ssm(SCI_GETCURRENTPOS)
|
||
|
end function
|
||
|
|
||
|
global function get_selection()
|
||
|
integer len
|
||
|
atom buf
|
||
|
sequence text
|
||
|
|
||
|
len = ssm(SCI_GETSELTEXT)
|
||
|
if len <= 1 then
|
||
|
return ""
|
||
|
end if
|
||
|
buf = allocate(len)
|
||
|
ssm(SCI_GETSELTEXT, 0, buf)
|
||
|
text = peek({buf, len - 1})
|
||
|
free(buf)
|
||
|
return text
|
||
|
end function
|
||
|
|
||
|
global procedure set_top_line(integer line)
|
||
|
integer fv, los
|
||
|
if line = -1 then
|
||
|
line = ssm(SCI_LINEFROMPOSITION, get_pos())
|
||
|
end if
|
||
|
fv = ssm(SCI_GETFIRSTVISIBLELINE)
|
||
|
los = ssm(SCI_LINESONSCREEN)
|
||
|
if line >= fv and line < fv + los-1 then
|
||
|
return -- don't need to scroll
|
||
|
end if
|
||
|
line = ssm(SCI_SETFIRSTVISIBLELINE, line)
|
||
|
end procedure
|
||
|
|
||
|
global function get_modified()
|
||
|
return ssm(SCI_GETMODIFY)
|
||
|
end function
|
||
|
|
||
|
global function get_line_length(integer line)
|
||
|
if line = -1 then
|
||
|
line = ssm(SCI_LINEFROMPOSITION, get_pos())
|
||
|
end if
|
||
|
return ssm(SCI_LINELENGTH, line)
|
||
|
end function
|
||
|
|
||
|
global function get_line_end_position(integer line)
|
||
|
if line = -1 then
|
||
|
line = ssm(SCI_LINEFROMPOSITION, get_pos())
|
||
|
end if
|
||
|
return ssm(SCI_GETLINEENDPOSITION, line)
|
||
|
end function
|
||
|
|
||
|
global function get_line_start_position(integer line)
|
||
|
if line = -1 then
|
||
|
line = ssm(SCI_LINEFROMPOSITION, get_pos())
|
||
|
end if
|
||
|
return ssm(SCI_POSITIONFROMLINE, line)
|
||
|
end function
|
||
|
|
||
|
|
||
|
global function get_line(integer line)
|
||
|
atom junk, len, buf
|
||
|
sequence text
|
||
|
|
||
|
if line = -1 then
|
||
|
line = ssm(SCI_LINEFROMPOSITION, get_pos())
|
||
|
end if
|
||
|
len = get_line_length(line)
|
||
|
buf = allocate(len+1)
|
||
|
ssm(SCI_GETLINE, line, buf)
|
||
|
text = peek({buf, len})
|
||
|
free(buf)
|
||
|
return text
|
||
|
end function
|
||
|
|
||
|
global function get_edit_text()
|
||
|
atom junk, text_buffer, text_len
|
||
|
sequence text
|
||
|
|
||
|
text_len = ssm(SCI_GETTEXTLENGTH)+1
|
||
|
text_buffer = allocate(text_len)
|
||
|
ssm(SCI_GETTEXT, text_len, text_buffer)
|
||
|
text = peek({text_buffer, text_len-1})
|
||
|
free(text_buffer)
|
||
|
return text
|
||
|
end function
|
||
|
|
||
|
global procedure update_status()
|
||
|
atom pos, line, col
|
||
|
pos = get_pos()
|
||
|
line = 1+ssm(SCI_LINEFROMPOSITION, pos)
|
||
|
col = 1+ssm(SCI_GETCOLUMN, pos)
|
||
|
ui_update_status(sprintf("%d:%d ", {line, col}))
|
||
|
if line-1 != expand_line then
|
||
|
expand_line = -1
|
||
|
end if
|
||
|
end procedure
|
||
|
|
||
|
|
||
|
--------------------------------------
|
||
|
-- search and replace
|
||
|
--------------------------------------
|
||
|
|
||
|
-- search for the phrase (sequence or pointer) and set the editor target
|
||
|
-- returns 1 if found, otherwise 0
|
||
|
global function search_find(sequence phrase, integer backward = 0, integer in_replace_all = 0)
|
||
|
if backward then
|
||
|
ssm(SCI_SETTARGETSTART, ssm(SCI_GETSELECTIONSTART))
|
||
|
ssm(SCI_SETTARGETEND, 0)
|
||
|
else
|
||
|
ssm(SCI_SETTARGETSTART, ssm(SCI_GETSELECTIONEND))
|
||
|
ssm(SCI_SETTARGETEND, ssm(SCI_GETTEXTLENGTH))
|
||
|
end if
|
||
|
|
||
|
if ssm(SCI_SEARCHINTARGET, length(phrase), phrase) < 0 then
|
||
|
-- wrap around and search again
|
||
|
if in_replace_all then
|
||
|
return 0
|
||
|
elsif backward then
|
||
|
ssm(SCI_SETTARGETSTART, ssm(SCI_GETTEXTLENGTH))
|
||
|
else
|
||
|
ssm(SCI_SETTARGETSTART, 0)
|
||
|
end if
|
||
|
if ssm(SCI_SEARCHINTARGET, length(phrase), phrase) < 0 then
|
||
|
-- clear the target so search_replace won't do bad things
|
||
|
ssm(SCI_SETTARGETSTART, 0)
|
||
|
ssm(SCI_SETTARGETEND, 0)
|
||
|
return 0
|
||
|
end if
|
||
|
end if
|
||
|
-- scroll to left side first
|
||
|
ssm(SCI_SETXOFFSET, 0)
|
||
|
-- set selection from target
|
||
|
ssm(SCI_SETSEL, ssm(SCI_GETTARGETSTART), ssm(SCI_GETTARGETEND))
|
||
|
|
||
|
return 1
|
||
|
end function
|
||
|
|
||
|
-- replace the editor target with the phrase (sequence or pointer)
|
||
|
-- returns 1 if replace made, otherwise 0
|
||
|
global function search_replace(sequence phrase)
|
||
|
integer pos = ssm(SCI_GETTARGETSTART)
|
||
|
if pos >= ssm(SCI_GETTARGETEND) then
|
||
|
-- target not set
|
||
|
if not equal(get_selection(), find_phrase) then
|
||
|
return 0
|
||
|
end if
|
||
|
SSM(hedit, SCI_TARGETFROMSELECTION)
|
||
|
end if
|
||
|
-- replace or replace_all
|
||
|
ssm(SCI_REPLACETARGET, length(phrase), phrase)
|
||
|
-- set the current pos to the end, so that the next
|
||
|
-- find doesn't search within the replacement phrase
|
||
|
ssm(SCI_SETSEL, pos, pos + length(phrase))
|
||
|
return 1
|
||
|
end function
|
||
|
|
||
|
-- replace all in document, saving the cursor position
|
||
|
-- returns count of replacements made
|
||
|
global function search_replace_all(sequence what, sequence phrase)
|
||
|
integer
|
||
|
pos = ssm(SCI_GETCURRENTPOS),
|
||
|
anchor = ssm(SCI_GETANCHOR),
|
||
|
count = 0
|
||
|
-- save the current position to be restored later
|
||
|
ssm(SCI_SETANCHOR, 0)
|
||
|
ssm(SCI_SETCURRENTPOS, 0)
|
||
|
-- search until not found
|
||
|
ssm(SCI_BEGINUNDOACTION)
|
||
|
while search_find(what, 0, 1) do
|
||
|
search_replace(phrase)
|
||
|
count += 1
|
||
|
end while
|
||
|
ssm(SCI_ENDUNDOACTION)
|
||
|
ssm(SCI_SETSEL, anchor, pos)
|
||
|
return count
|
||
|
end function
|
||
|
|
||
|
|
||
|
--------------------------------------
|
||
|
-- tab management
|
||
|
--------------------------------------
|
||
|
|
||
|
global function get_prev_tab()
|
||
|
if current_tab <= 1 then
|
||
|
return length(tab_hedits)
|
||
|
end if
|
||
|
return current_tab - 1
|
||
|
end function
|
||
|
|
||
|
global function get_next_tab()
|
||
|
if current_tab >= length(tab_hedits) then
|
||
|
return 1
|
||
|
end if
|
||
|
return current_tab + 1
|
||
|
end function
|
||
|
|
||
|
global function make_tab_name()
|
||
|
sequence name
|
||
|
|
||
|
if length(file_name) = 0 then
|
||
|
name = "New File"
|
||
|
else
|
||
|
name = file_name
|
||
|
for i = length(name) to 1 by -1 do
|
||
|
if name[i] = '\\' or name[i] = '/' then
|
||
|
name = name[i+1..$]
|
||
|
exit
|
||
|
end if
|
||
|
end for
|
||
|
end if
|
||
|
return name
|
||
|
end function
|
||
|
|
||
|
|
||
|
procedure update_tab_timestamp()
|
||
|
if length(file_name) then
|
||
|
tab_timestamps[current_tab] = get_timestamp(file_name)
|
||
|
else
|
||
|
tab_timestamps[current_tab] = -1
|
||
|
end if
|
||
|
end procedure
|
||
|
|
||
|
|
||
|
global procedure select_tab(integer tab)
|
||
|
if tab < 1 or tab > length(tab_hedits) or tab = current_tab then
|
||
|
return
|
||
|
end if
|
||
|
current_tab = tab
|
||
|
file_name = tab_file_names[tab]
|
||
|
hedit = tab_hedits[tab]
|
||
|
modified = get_modified()
|
||
|
|
||
|
expand_line = -1
|
||
|
insert_chars = ""
|
||
|
calltip_args = {}
|
||
|
calltip_pos = -1
|
||
|
calltip_stack = {}
|
||
|
calltip_text = ""
|
||
|
last_errors = {}
|
||
|
ui_select_tab(tab)
|
||
|
ui_update_window_title(make_tab_name())
|
||
|
update_status()
|
||
|
|
||
|
update_lexer()
|
||
|
change_time = time() + .5
|
||
|
end procedure
|
||
|
|
||
|
global procedure update_tab_name()
|
||
|
sequence name = make_tab_name()
|
||
|
ui_update_window_title(name)
|
||
|
if modified then name &= "*" end if
|
||
|
ui_update_tab_name(current_tab, name)
|
||
|
end procedure
|
||
|
|
||
|
global procedure new_tab(sequence file_name)
|
||
|
integer tab
|
||
|
|
||
|
if equal(tab_file_names, {""}) and modified = 0 then
|
||
|
-- unmodified new file, just reuse it and update the tab name
|
||
|
tab = 1
|
||
|
tab_file_names[tab] = file_name
|
||
|
update_tab_name()
|
||
|
current_tab = 0 -- to force select_tab
|
||
|
else
|
||
|
hedit = ui_new_tab(make_tab_name())
|
||
|
|
||
|
tab_hedits = append(tab_hedits, hedit)
|
||
|
tab_file_names = append(tab_file_names, file_name)
|
||
|
tab_timestamps = append(tab_timestamps, -1)
|
||
|
tab_arguments = append(tab_arguments, "")
|
||
|
tab_pos_stack = append(tab_pos_stack, {})
|
||
|
tab = length(tab_hedits)
|
||
|
end if
|
||
|
select_tab(tab)
|
||
|
init_edit(hedit)
|
||
|
ssm(SCI_SETINDENT, 4)
|
||
|
ssm(SCI_SETUSETABS, 0)
|
||
|
end procedure
|
||
|
|
||
|
global procedure close_tab()
|
||
|
integer tab
|
||
|
|
||
|
if save_if_modified(1) = 0 then
|
||
|
return -- user cancelled the save
|
||
|
end if
|
||
|
|
||
|
tab = current_tab
|
||
|
save_recent_pos()
|
||
|
ui_close_tab(tab)
|
||
|
|
||
|
tab_hedits = tab_hedits[1..tab-1] & tab_hedits[tab+1..$]
|
||
|
tab_file_names = tab_file_names[1..tab-1] & tab_file_names[tab+1..$]
|
||
|
tab_timestamps = tab_timestamps[1..tab-1] & tab_timestamps[tab+1..$]
|
||
|
tab_arguments = tab_arguments[1..tab-1] & tab_arguments[tab+1..$]
|
||
|
tab_pos_stack = tab_pos_stack[1..tab-1] & tab_pos_stack[tab+1..$]
|
||
|
current_tab = 0
|
||
|
if length(tab_hedits) = 0 then
|
||
|
new_file() -- must always have a edit available
|
||
|
elsif tab > length(tab_hedits) then
|
||
|
tab = length(tab_hedits)
|
||
|
end if
|
||
|
select_tab(tab)
|
||
|
end procedure
|
||
|
|
||
|
global function get_tab_arguments()
|
||
|
return tab_arguments[current_tab]
|
||
|
end function
|
||
|
|
||
|
global procedure set_tab_arguments(sequence s)
|
||
|
tab_arguments[current_tab] = s
|
||
|
end procedure
|
||
|
|
||
|
|
||
|
|
||
|
--------------------------------------
|
||
|
-- file open/save
|
||
|
--------------------------------------
|
||
|
|
||
|
-- returns tab index of opened file, or 0 if cancelled
|
||
|
global function open_file(sequence file_name, integer reload)
|
||
|
atom result, text_buffer
|
||
|
integer fn, tab, initial_pos = 0, first_visible_line = 0
|
||
|
object temp, s
|
||
|
sequence text
|
||
|
|
||
|
if length(file_name) = 0 then
|
||
|
file_name = ui_get_open_file_name()
|
||
|
if length(file_name) = 0 then return 0 end if
|
||
|
if sequence(file_name[1]) then
|
||
|
-- multiple open
|
||
|
for i = 1 to length(file_name) do
|
||
|
open_file(file_name[i], reload)
|
||
|
end for
|
||
|
return 0
|
||
|
end if
|
||
|
elsif sequence(file_name[1]) then
|
||
|
-- filename is {"file_name", initial_pos, first_visible_line}
|
||
|
if length(file_name) >= 2 and integer(file_name[2]) then
|
||
|
initial_pos = file_name[2]
|
||
|
end if
|
||
|
if length(file_name) >= 3 and integer(file_name[3]) then
|
||
|
first_visible_line = file_name[3]
|
||
|
end if
|
||
|
file_name = file_name[1]
|
||
|
end if
|
||
|
|
||
|
file_name = canonical_path(file_name, 0, CORRECT)
|
||
|
|
||
|
-- check if already existing tab
|
||
|
tab = find(file_name, tab_file_names)
|
||
|
if tab and reload = 0 then
|
||
|
select_tab(tab)
|
||
|
return tab
|
||
|
end if
|
||
|
|
||
|
text = ""
|
||
|
fn = open(file_name, "rb")
|
||
|
if fn = -1 then
|
||
|
-- file couldn't be opened
|
||
|
if ui_message_box_yes_no("Open", "Unable to open "&file_name&"\n\n"&
|
||
|
"Do you want to create it?") = 0 then
|
||
|
return 0
|
||
|
end if
|
||
|
else
|
||
|
-- read the contents of the file into text
|
||
|
s = gets(fn)
|
||
|
while sequence(s) do
|
||
|
text &= s
|
||
|
s = gets(fn)
|
||
|
end while
|
||
|
close(fn)
|
||
|
end if
|
||
|
|
||
|
if not tab then
|
||
|
new_tab(file_name)
|
||
|
tab = current_tab
|
||
|
end if
|
||
|
update_tab_timestamp()
|
||
|
|
||
|
result = ssm(SCI_CLEARALL)
|
||
|
result = ssm(SCI_SETTEXT, 0, text)
|
||
|
result = ssm(SCI_SETSAVEPOINT)
|
||
|
modified = 0
|
||
|
if tab then
|
||
|
update_tab_name()
|
||
|
end if
|
||
|
|
||
|
result = ssm(SCI_SETFIRSTVISIBLELINE, first_visible_line)
|
||
|
result = ssm(SCI_SETEMPTYSELECTION, initial_pos)
|
||
|
result = ssm(SCI_EMPTYUNDOBUFFER)
|
||
|
auto_detect_indent(text)
|
||
|
|
||
|
add_recent_file(file_name)
|
||
|
return tab
|
||
|
end function
|
||
|
|
||
|
-- open files on startup and saved tabs
|
||
|
global procedure open_tabs()
|
||
|
sequence cmdline
|
||
|
-- open files from previous session
|
||
|
for i = 1 to length(tabs_to_open) do
|
||
|
if file_exists(tabs_to_open[i][1]) then
|
||
|
open_file(tabs_to_open[i], 0)
|
||
|
end if
|
||
|
end for
|
||
|
-- open files on command line
|
||
|
cmdline = command_line()
|
||
|
for i = 3 to length(cmdline) do
|
||
|
open_file(cmdline[i], 0)
|
||
|
end for
|
||
|
if length(tab_file_names) = 0 and length(cmdline) < 3 then
|
||
|
new_file()
|
||
|
elsif length(cmdline) < 3 then
|
||
|
-- select initial tab if no files on command line
|
||
|
select_tab(initial_tab)
|
||
|
end if
|
||
|
end procedure
|
||
|
|
||
|
-- returns 1 if ok, 0 on error
|
||
|
function save_file()
|
||
|
atom fn, junk
|
||
|
sequence text
|
||
|
|
||
|
ssm(SCI_SETSAVEPOINT, 0, 0)
|
||
|
modified = 0
|
||
|
|
||
|
fn = open(file_name, "wb")
|
||
|
if fn = -1 then
|
||
|
ui_message_box_error("Save", "Unable to save file. Please make sure the file location is not read-only.")
|
||
|
return 0
|
||
|
end if
|
||
|
text = get_edit_text()
|
||
|
puts(fn, text)
|
||
|
junk = where(fn)
|
||
|
close(fn)
|
||
|
|
||
|
if junk != length(text) then
|
||
|
ui_message_box_error("Save", "The file could not be written completely. Please make sure there is enough free space.")
|
||
|
return 0
|
||
|
end if
|
||
|
|
||
|
update_tab_name()
|
||
|
update_tab_timestamp()
|
||
|
return 1
|
||
|
end function
|
||
|
|
||
|
global function save_file_as() -- returns 1 if ok, 0 if cancelled/error
|
||
|
object temp
|
||
|
|
||
|
temp = ui_get_save_file_name(file_name)
|
||
|
if length(temp) = 0 then return 0 end if
|
||
|
|
||
|
file_name = canonical_path(temp, 0, CORRECT)
|
||
|
tab_file_names[current_tab] = file_name
|
||
|
if save_file() = 0 then
|
||
|
return 0
|
||
|
end if
|
||
|
update_tab_name()
|
||
|
update_lexer()
|
||
|
return 1
|
||
|
end function
|
||
|
|
||
|
|
||
|
global function save_if_modified(integer confirm) -- returns 1 if ok, 0 if cancelled/error
|
||
|
atom result, junk
|
||
|
sequence text
|
||
|
|
||
|
if not get_modified() and (length(file_name) != 0 or confirm) then
|
||
|
return 1
|
||
|
end if
|
||
|
|
||
|
if confirm then
|
||
|
text = ""
|
||
|
if length(file_name) then
|
||
|
text = " in " & file_name
|
||
|
end if
|
||
|
text = "The text"&text&" has changed.\n\nDo you want to save the changes?"
|
||
|
result = ui_message_box_yes_no_cancel(window_title, text)
|
||
|
if result != 1 then -- no or cancel
|
||
|
return result + 1
|
||
|
end if
|
||
|
end if
|
||
|
|
||
|
if length(file_name) = 0 then
|
||
|
return save_file_as()
|
||
|
end if
|
||
|
return save_file()
|
||
|
end function
|
||
|
|
||
|
global function save_modified_tabs() --returns 1 if ok, 0 if cancelled
|
||
|
integer idx
|
||
|
atom saved_hedit
|
||
|
saved_hedit = hedit
|
||
|
for tab = 1 to length(tab_hedits) do
|
||
|
hedit = tab_hedits[tab]
|
||
|
idx = find(tab_file_names[tab], recent_files)
|
||
|
if idx then
|
||
|
recent_pos[idx] = get_pos()
|
||
|
end if
|
||
|
if get_modified() then
|
||
|
select_tab(tab)
|
||
|
if save_if_modified(1) = 0 then
|
||
|
return 0 -- cancelled
|
||
|
end if
|
||
|
saved_hedit = hedit
|
||
|
end if
|
||
|
end for
|
||
|
hedit = saved_hedit
|
||
|
return 1
|
||
|
end function
|
||
|
|
||
|
global procedure new_file()
|
||
|
atom junk
|
||
|
|
||
|
new_tab("")
|
||
|
ssm(SCI_SETTEXT, 0, "")
|
||
|
ssm(SCI_SETSAVEPOINT, 0, 0)
|
||
|
end procedure
|
||
|
|
||
|
|
||
|
global procedure check_externally_modified_tabs()
|
||
|
atom ts
|
||
|
for i = 1 to length(tab_file_names) do
|
||
|
if length(tab_file_names[i]) and tab_timestamps[i] != -1 then
|
||
|
ts = get_timestamp(tab_file_names[i])
|
||
|
if ts != tab_timestamps[i] then
|
||
|
-- clear the timestamp here so that don't repeat when the MessageBox retriggers WM_SETFOCUS
|
||
|
tab_timestamps[i] = -1
|
||
|
if ui_message_box_yes_no(window_title, tab_file_names[i] &
|
||
|
"\n\nThis file has been modified by another application. Do you want to reload it?") then
|
||
|
integer pos
|
||
|
select_tab(i)
|
||
|
pos = get_pos()
|
||
|
open_file(tab_file_names[i], 1)
|
||
|
goto_pos(pos)
|
||
|
else
|
||
|
tab_timestamps[i] = ts
|
||
|
end if
|
||
|
end if
|
||
|
end if
|
||
|
end for
|
||
|
end procedure
|
||
|
|
||
|
|
||
|
global procedure add_recent_file(sequence filename)
|
||
|
integer idx
|
||
|
idx = find(filename, recent_files)
|
||
|
if idx then
|
||
|
-- move it to the top of the list
|
||
|
recent_files = {recent_files[idx]} & recent_files[1..idx-1] &
|
||
|
recent_files[idx+1..length(recent_files)]
|
||
|
recent_pos = {recent_pos[idx]} & recent_pos[1..idx-1] &
|
||
|
recent_pos[idx+1..length(recent_pos)]
|
||
|
else
|
||
|
idx = length(recent_files)
|
||
|
if idx >= max_recent_files then
|
||
|
idx -= 1
|
||
|
end if
|
||
|
recent_files = {filename} & recent_files[1..idx]
|
||
|
recent_pos = {0} & recent_pos[1..idx]
|
||
|
end if
|
||
|
ui_refresh_file_menu(recent_files)
|
||
|
end procedure
|
||
|
|
||
|
global procedure save_recent_pos()
|
||
|
integer idx
|
||
|
idx = find(file_name, recent_files)
|
||
|
if idx then
|
||
|
recent_pos[idx] = get_pos()
|
||
|
end if
|
||
|
end procedure
|
||
|
|
||
|
global procedure open_recent(integer idx)
|
||
|
atom junk
|
||
|
integer tab
|
||
|
if idx >= 1 and idx <= length(recent_files) then
|
||
|
tab = open_file(recent_files[idx], 0)
|
||
|
if tab then
|
||
|
ssm(SCI_SETSEL, recent_pos[1], recent_pos[1])
|
||
|
set_top_line(-1) -- set the top visible line to the current line
|
||
|
end if
|
||
|
end if
|
||
|
end procedure
|
||
|
|
||
|
|
||
|
--------------------------------------
|
||
|
-- help routines
|
||
|
--------------------------------------
|
||
|
|
||
|
sequence help_dir
|
||
|
|
||
|
function tr(sequence s, sequence src, sequence dst)
|
||
|
for i = 1 to length(s) do
|
||
|
integer x = find(s[i], src)
|
||
|
if x then
|
||
|
s[i] = dst[x]
|
||
|
end if
|
||
|
end for
|
||
|
return s
|
||
|
end function
|
||
|
|
||
|
global procedure context_help()
|
||
|
sequence text, decls, word, name_space, path
|
||
|
integer pos, junk
|
||
|
object help
|
||
|
|
||
|
text = get_edit_text()
|
||
|
pos = get_pos()
|
||
|
word = word_pos(text, pos)
|
||
|
if length(word) < 2 then
|
||
|
name_space = ""
|
||
|
word = ""
|
||
|
else
|
||
|
name_space = word[2]
|
||
|
word = word[1]
|
||
|
end if
|
||
|
|
||
|
-- load the search.dat file
|
||
|
if length(search_dat) = 0 then
|
||
|
sequence paths = include_search_paths
|
||
|
for i = 1 to length(paths) do
|
||
|
path = paths[i]
|
||
|
if path[$] = SLASH then
|
||
|
path = path[1..$-1]
|
||
|
end if
|
||
|
path &= join_path({"..","docs","html"}) & SLASH
|
||
|
--puts(1, path&"\n")
|
||
|
integer f = open(path & "js" & SLASH & "search.js","r")
|
||
|
if f != -1 then
|
||
|
help_dir = canonical_path(path)
|
||
|
if help_dir[$] != SLASH then
|
||
|
help_dir &= SLASH
|
||
|
end if
|
||
|
object line = gets(f)
|
||
|
while sequence(line) do
|
||
|
integer x = find(':', line)
|
||
|
if x and line[1] = '"' then
|
||
|
--puts(1, line[2..x-2]&" "&line[x+1..$]&"\n")
|
||
|
search_idx = append(search_idx, line[2..x-2])
|
||
|
line = tr(line[x+1..$-1], "[]", "{}")
|
||
|
line = value(line)
|
||
|
search_dat = append(search_dat, line[2])
|
||
|
end if
|
||
|
line = gets(f)
|
||
|
end while
|
||
|
close(f)
|
||
|
exit
|
||
|
end if
|
||
|
end for
|
||
|
if length(search_dat) = 0 then
|
||
|
ui_message_box_error(window_title, "File not found: euphoria/docs/html/js/search.js")
|
||
|
return
|
||
|
end if
|
||
|
end if
|
||
|
|
||
|
-- search search.dat for matching entry
|
||
|
help = {}
|
||
|
for i = 1 to length(search_idx) do
|
||
|
if equal(search_idx[i], word) then
|
||
|
help = search_dat[i]
|
||
|
exit
|
||
|
end if
|
||
|
end for
|
||
|
if atom(help) or length(help) = 0 then
|
||
|
ui_message_box_error("Help",
|
||
|
"Didn't find any help on the topic: "&word&
|
||
|
"\nPlease put the cursor over an Euphoria identifier"&
|
||
|
"\nor standard library routine and try again.")
|
||
|
return
|
||
|
end if
|
||
|
|
||
|
if length(help) > 1 then
|
||
|
-- multiple help entries
|
||
|
path = ""
|
||
|
decls = get_declarations(parse(text, file_name), pos, name_space)
|
||
|
for j = 1 to length(decls) by 2 do
|
||
|
if equal(decls[j], word) then
|
||
|
if atom(decls[j+1]) then
|
||
|
path = file_name
|
||
|
else
|
||
|
path = decls[j+1][1]
|
||
|
end if
|
||
|
|
||
|
for i = 1 to length(help) do
|
||
|
if match(sreplace(help[i][1],"_",{SLASH})&".e", path) then
|
||
|
--show_help(help[i][1], help[i][2])
|
||
|
ui_show_uri("file://" & help_dir & help[i][1] & ".html#" & help[i][2])
|
||
|
return
|
||
|
end if
|
||
|
end for
|
||
|
end if
|
||
|
end for
|
||
|
end if
|
||
|
|
||
|
-- only one help entry, just show it
|
||
|
--show_help(help[1][1], help[1][2])
|
||
|
ui_show_uri("file://" & help_dir & help[1][1] & ".html#" & help[1][2])
|
||
|
end procedure
|
||
|
|
||
|
global procedure release_notes()
|
||
|
new_file()
|
||
|
ssm(SCI_SETLEXER, SCLEX_NULL)
|
||
|
ssm(SCI_SETTEXT, 0, changelog)
|
||
|
ssm(SCI_SETSAVEPOINT)
|
||
|
end procedure
|
||
|
|
||
|
global procedure open_tutorial()
|
||
|
new_file()
|
||
|
ssm(SCI_SETTEXT, 0, `
|
||
|
----------------------------------------
|
||
|
-- Welcome to the Wee Euphoria Editor --
|
||
|
----------------------------------------
|
||
|
|
||
|
-- Scintilla Keys:
|
||
|
--
|
||
|
-- Text Size
|
||
|
-- Magnify Control keypad +
|
||
|
-- Reduce Control keypad -
|
||
|
-- Normal Control keypad /
|
||
|
--
|
||
|
-- Cursor Movement
|
||
|
-- Go to start of document Control Home
|
||
|
-- Go to end of document Control End
|
||
|
-- Go to start of line Home
|
||
|
-- Go to end of line End
|
||
|
-- Go to previous paragraph Control Up
|
||
|
-- Go to next paragraph Control Down
|
||
|
-- Go to previous word Control Left
|
||
|
-- Go to next word Control Right
|
||
|
-- (shift extends selection)
|
||
|
--
|
||
|
-- Delete Text
|
||
|
-- To start of line Control Shift Backspace
|
||
|
-- To start of word Control Backspace
|
||
|
-- To end of word Control Delete
|
||
|
--
|
||
|
-- Indent
|
||
|
-- Indent block Tab
|
||
|
-- Unindent block Shift Tab
|
||
|
-- Comment/uncomment block Control M
|
||
|
|
||
|
-- Editor Tab Management
|
||
|
-- Switch to next tab Control PgDn / Control Tab
|
||
|
-- Switch to previous tab Control PgUp / Shift Control Tab
|
||
|
-- Switch tabs Mouse wheel
|
||
|
-- Tab menu Right click
|
||
|
-- Close tab Middle click
|
||
|
|
||
|
-- Wee offers autocompletion for the following keywords.
|
||
|
-- Type a space at the end of each keyword below to see the
|
||
|
-- expansion. After the expansion, press Enter to jump over
|
||
|
-- the "then" or "do" to the next line.
|
||
|
|
||
|
if
|
||
|
|
||
|
-------------------------
|
||
|
while
|
||
|
|
||
|
-------------------------
|
||
|
switch
|
||
|
|
||
|
-------------------------
|
||
|
procedure
|
||
|
|
||
|
-------------------------
|
||
|
function
|
||
|
|
||
|
-------------------------
|
||
|
type
|
||
|
|
||
|
-------------------------
|
||
|
for
|
||
|
|
||
|
-- The "for" keyword also inserts " = to " but is overtypable,
|
||
|
-- meaning you can continue typing " = " and it will replace the
|
||
|
-- existing characters. Or you can move your cursor using the
|
||
|
-- arrow keys.
|
||
|
|
||
|
-- Likewise, pair characters are inserted for typing the following
|
||
|
-- characters: ( [ { " '
|
||
|
-- And you can overtype the closing character if you wish.
|
||
|
-- Pressing "(" results in "()"
|
||
|
-- Typing "123" results in "(123)"
|
||
|
-- Pressing ")" results in "(123)"
|
||
|
-- Try it!
|
||
|
|
||
|
-- Here's a longer example demonstrating the overtype mechanism:
|
||
|
|
||
|
-- type result
|
||
|
-- ------- ---------------------
|
||
|
-- foo[ foo[]
|
||
|
-- 123 foo[123]
|
||
|
-- ] foo[123]
|
||
|
-- [ foo[123][]
|
||
|
-- ( foo[123][()]
|
||
|
-- i+1 foo[123][(i+1)]
|
||
|
-- )*2 foo[123][(i+1)*2]
|
||
|
-- ] foo[123][(i+1)*2]
|
||
|
-- = { foo[123][(i+1)*2] = {}
|
||
|
-- 1, { foo[123][(i+1)*2] = {1, {}}
|
||
|
-- " foo[123][(i+1)*2] = {1, {""}}
|
||
|
-- bar foo[123][(i+1)*2] = {1, {"bar"}}
|
||
|
-- " foo[123][(i+1)*2] = {1, {"bar"}}
|
||
|
-- } foo[123][(i+1)*2] = {1, {"bar"}}
|
||
|
-- } foo[123][(i+1)*2] = {1, {"bar"}}
|
||
|
|
||
|
|
||
|
-- If the initial character is deleted using backspace, the
|
||
|
-- inserted pair will also be removed. (This does not work
|
||
|
-- with quotation marks however, only parens and braces.)
|
||
|
-- Pressing "(" results in "()"
|
||
|
-- Pressing backspace results in ""
|
||
|
|
||
|
-- Wee also knows about subroutines you've defined.
|
||
|
-- Press F2 to see a list. If you've filled in names for the
|
||
|
-- subroutine declarations above, they should appear.
|
||
|
-- Pressing OK or Enter will move the cursor to the subroutine
|
||
|
-- definition. If your cursor is on the name of an existing
|
||
|
-- subroutine, it will be the highlighted entry.
|
||
|
-- Try it! Type the name of a subroutine and hit F2.
|
||
|
|
||
|
|
||
|
-- Autocompletion for any type of identifier is done with
|
||
|
-- Control+Space. The standard library is also searched for
|
||
|
-- completions, indicated by "--include" in the list entry, and
|
||
|
-- when selected, the include statement will be inserted
|
||
|
-- automatically near the top of the file.
|
||
|
|
||
|
|
||
|
-- Typing ':' after a namespace identifier will show an auto-
|
||
|
-- complete list for definitions within a specific namespace.
|
||
|
|
||
|
|
||
|
-- Pressing Ctrl+F2 while on an identifier will move the cursor
|
||
|
-- to the definition of that identifier, and select it.
|
||
|
-- Pressing escape will deselect the text, and pressing escape
|
||
|
-- again will return the cursor to the previous location, think
|
||
|
-- of it as pressing Back in a web browser.
|
||
|
|
||
|
|
||
|
-- Pressing Shift+F2 while on a subroutine identifier will display
|
||
|
-- a calltips popup. The popup shows the types and names of the
|
||
|
-- arguments to the subroutine, with default arguments enclosed in
|
||
|
-- square brackets.
|
||
|
|
||
|
|
||
|
-- Typing '(' after a subroutine identifier will show the calltips
|
||
|
-- popup, and highlight the argument position as you type.
|
||
|
|
||
|
|
||
|
-- Pressing F4 will open a dialog showing the most recent ex.err
|
||
|
-- file, with the error message and a list of either:
|
||
|
-- the call stack of the subroutines at the point of the crash,
|
||
|
-- or a list of undefined symbols.
|
||
|
-- Select an item in the list and press Goto Error to move the
|
||
|
-- cursor to that location.
|
||
|
|
||
|
|
||
|
-- That's all, have fun!
|
||
|
`)
|
||
|
ssm(SCI_SETSAVEPOINT)
|
||
|
end procedure
|
||
|
|
||
|
|
||
|
|
||
|
-------------------------------------------------------------------
|
||
|
-- ex.err file handling routines
|
||
|
-------------------------------------------------------------------
|
||
|
|
||
|
-- returns {"filename:line", "message", "line1", "line2", "line3"...}
|
||
|
global function get_ex_err()
|
||
|
integer fn
|
||
|
object line, msg, txt
|
||
|
sequence result, tmp
|
||
|
|
||
|
fn = open(ex_err_name, "r")
|
||
|
if fn = -1 then
|
||
|
return {}
|
||
|
end if
|
||
|
result = {}
|
||
|
line = gets(fn) -- filename:line
|
||
|
if not atom(line) then
|
||
|
msg = gets(fn)
|
||
|
result = {line, msg}
|
||
|
if match("Errors resolving the following references", msg) then
|
||
|
txt = gets(fn)
|
||
|
while sequence(txt) and length(txt) > 1 do
|
||
|
result = append(result, txt)
|
||
|
txt = gets(fn)
|
||
|
end while
|
||
|
else
|
||
|
result = append(result, line)
|
||
|
tmp = "... called from "
|
||
|
txt = gets(fn)
|
||
|
while sequence(txt) and length(result) < 100 do
|
||
|
if length(txt) > length(tmp) and equal(txt[1..length(tmp)], tmp) then
|
||
|
result = append(result, txt[length(tmp)+1..$])
|
||
|
end if
|
||
|
txt = gets(fn)
|
||
|
end while
|
||
|
end if
|
||
|
end if
|
||
|
close(fn)
|
||
|
return result
|
||
|
end function
|
||
|
|
||
|
-- get the text between two delimeters, searching from end of text
|
||
|
function text_between(sequence text, integer delim1, integer delim2)
|
||
|
for i = length(text) to 1 by -1 do
|
||
|
if text[i] = delim2 then
|
||
|
for j = i-1 to 1 by -1 do
|
||
|
if text[j] = delim1 then
|
||
|
return text[j+1..i-1]
|
||
|
end if
|
||
|
end for
|
||
|
exit
|
||
|
end if
|
||
|
end for
|
||
|
return ""
|
||
|
end function
|
||
|
|
||
|
global procedure goto_error(sequence err, integer idx)
|
||
|
integer a, b, c, line, tab, col
|
||
|
sequence val, file, item, text
|
||
|
|
||
|
if idx < 0 or idx > length(err)-2 then
|
||
|
return
|
||
|
end if
|
||
|
|
||
|
text = err[idx+2]
|
||
|
|
||
|
a = find('(', text)
|
||
|
b = find(')', text)
|
||
|
c = 0
|
||
|
for i = length(text) to 1 by -1 do
|
||
|
if text[i] = ':' then
|
||
|
c = i
|
||
|
exit
|
||
|
end if
|
||
|
end for
|
||
|
item = ""
|
||
|
if a < c and c < b then
|
||
|
-- 'blah' (filename:line) has not been declared
|
||
|
file = dirname(ex_err_name) & SLASH & text[a+1..c-1]
|
||
|
val = value(text[c+1..b-1])
|
||
|
item = text_between(text, '\'', '\'')
|
||
|
elsif c then
|
||
|
-- c:\path\to\filename.ext:line subroutine_name()
|
||
|
file = text[1..c-1]
|
||
|
val = value(text[c+1..$])
|
||
|
item = text_between(err[2], '\'', '\'')
|
||
|
else
|
||
|
return
|
||
|
end if
|
||
|
tab = open_file(file, 0)
|
||
|
if tab and val[1] = GET_SUCCESS then
|
||
|
line = val[2]-1
|
||
|
col = 0
|
||
|
if length(item) then
|
||
|
col = match(item, get_line(line))
|
||
|
if col then
|
||
|
col -= 1
|
||
|
else
|
||
|
item = ""
|
||
|
end if
|
||
|
end if
|
||
|
col += ssm(SCI_POSITIONFROMLINE, line)
|
||
|
ssm(SCI_SETSEL, col, col + length(item))
|
||
|
set_top_line(line)
|
||
|
end if
|
||
|
end procedure
|
||
|
|
||
|
global procedure reset_ex_err()
|
||
|
if length(run_file_name) = 0 then
|
||
|
return
|
||
|
end if
|
||
|
ex_err_name = dirname(run_file_name) & SLASH & "ex.err"
|
||
|
ex_err_timestamp = get_timestamp(ex_err_name)
|
||
|
end procedure
|
||
|
|
||
|
global procedure check_ex_err()
|
||
|
atom ts
|
||
|
|
||
|
if length(run_file_name) = 0 then return end if
|
||
|
|
||
|
ts = get_timestamp(ex_err_name)
|
||
|
if ts > ex_err_timestamp then
|
||
|
run_file_name = ""
|
||
|
ui_view_error()
|
||
|
end if
|
||
|
ex_err_timestamp = ts
|
||
|
end procedure
|
||
|
|
||
|
|
||
|
-------------------------------------------------------------------
|
||
|
-- code syntax routines
|
||
|
-------------------------------------------------------------------
|
||
|
|
||
|
-- move to the declaration of the word under the cursor
|
||
|
global procedure view_declaration()
|
||
|
sequence text, decls, word, name_space
|
||
|
integer pos
|
||
|
|
||
|
text = get_edit_text()
|
||
|
pos = get_pos()
|
||
|
word = word_pos(text, pos)
|
||
|
if length(word) < 2 then return end if
|
||
|
name_space = word[2]
|
||
|
word = word[1]
|
||
|
|
||
|
decls = get_declarations(parse(text, file_name), pos, name_space)
|
||
|
for i = 1 to length(decls) do
|
||
|
if equal(decls[i][1], word) then
|
||
|
goto_pos(decls[i][2], length(word))
|
||
|
exit
|
||
|
end if
|
||
|
end for
|
||
|
end procedure
|
||
|
|
||
|
-- check the current document for errors, show underline indicators
|
||
|
procedure do_error_indicators()
|
||
|
if ssm(SCI_GETLEXER) != SCLEX_LUA then
|
||
|
return
|
||
|
end if
|
||
|
sequence text = get_edit_text()
|
||
|
sequence s = parse_errors(text, file_name)
|
||
|
if equal(s, last_errors) then
|
||
|
return
|
||
|
end if
|
||
|
last_errors = s
|
||
|
ssm(SCI_INDICATORCLEARRANGE, 0, ssm(SCI_GETTEXTLENGTH))
|
||
|
for i = 1 to length(s) by 3 do
|
||
|
ssm(SCI_INDICATORFILLRANGE, s[i]-1, s[i+1])
|
||
|
end for
|
||
|
end procedure
|
||
|
|
||
|
-- when the mouse hovers over an error, show the message in calltip
|
||
|
procedure dwell_error(integer dwell_pos)
|
||
|
integer pos, len
|
||
|
for i = 1 to length(last_errors) by 3 do
|
||
|
pos = last_errors[i]-1
|
||
|
len = last_errors[i+1]
|
||
|
if dwell_pos >= pos and dwell_pos < pos + len then
|
||
|
ssm(SCI_CALLTIPSHOW, pos, last_errors[i+2])
|
||
|
calltip_dwell = 1
|
||
|
return
|
||
|
end if
|
||
|
end for
|
||
|
end procedure
|
||
|
|
||
|
-- show a list of possible words when autocomplete is triggered
|
||
|
global procedure view_completions()
|
||
|
sequence text, word, ast, decls, name_space, suggestions
|
||
|
integer pos, junk, style, ns = 0
|
||
|
|
||
|
if ssm(SCI_AUTOCACTIVE) then
|
||
|
return -- autocomplete is already active
|
||
|
end if
|
||
|
|
||
|
pos = get_pos()
|
||
|
|
||
|
style = ssm(SCI_GETSTYLEAT, pos-2)
|
||
|
if style = SCE_LUA_STRING or style = SCE_LUA_COMMENTLINE then
|
||
|
return -- no completion in strings or comments
|
||
|
end if
|
||
|
|
||
|
-- use scintilla's code completion
|
||
|
text = get_edit_text()
|
||
|
word = word_pos(text, pos)
|
||
|
if length(word) < 4 then
|
||
|
return
|
||
|
end if
|
||
|
ssm(SCI_SETSEL, word[4], word[4])
|
||
|
name_space = word[2]
|
||
|
word = word[1]
|
||
|
|
||
|
ast = parse(text, file_name)
|
||
|
decls = get_declarations(ast, pos, name_space)
|
||
|
|
||
|
if length(decls) = 0 or length(name_space) = 0 then
|
||
|
suggestions = suggest_includes(word, name_space)
|
||
|
if length(suggestions) = 0 and length(word) = 0 and length(name_space) > 0 then
|
||
|
decls = get_declarations(ast, pos, "")
|
||
|
suggestions = suggest_includes(name_space, "")
|
||
|
ns = DECL_NAMESPACE
|
||
|
word = name_space
|
||
|
end if
|
||
|
|
||
|
-- filter duplicate suggestions
|
||
|
for i = 1 to length(suggestions) do
|
||
|
sequence tmp = suggestions[i]
|
||
|
if ns = 0 or tmp[3] = ns then
|
||
|
integer found = 0
|
||
|
tmp = {tmp[1], tmp[1][1..find(' ', tmp[1])-1]}
|
||
|
for j = 1 to length(decls) do
|
||
|
if find(decls[j][1], tmp) then
|
||
|
found = 1
|
||
|
exit
|
||
|
end if
|
||
|
end for
|
||
|
if not found then
|
||
|
decls = append(decls, suggestions[i])
|
||
|
end if
|
||
|
end if
|
||
|
end for
|
||
|
end if
|
||
|
|
||
|
text = ""
|
||
|
for i = 1 to length(decls) do
|
||
|
if (ns = 0 or decls[i][3] = ns)
|
||
|
and length(decls[i][1]) >= length(word)
|
||
|
and equal(decls[i][1][1..length(word)], word) then
|
||
|
if length(text) then
|
||
|
text &= "\n"
|
||
|
end if
|
||
|
text &= decls[i][1] & sprintf("?%d", {decls[i][3]})
|
||
|
end if
|
||
|
end for
|
||
|
if length(text) then
|
||
|
ssm(SCI_AUTOCSHOW, length(word) * (ns = 0), text)
|
||
|
end if
|
||
|
end procedure
|
||
|
|
||
|
-- show the subroutine arguments, usually triggered after a pressing '('
|
||
|
global procedure view_subroutine_arguments()
|
||
|
sequence text, word, decls, name_space
|
||
|
integer pos, end_pos, junk, calltip_save, style
|
||
|
|
||
|
pos = get_pos()
|
||
|
style = ssm(SCI_GETSTYLEAT, pos-2)
|
||
|
if style = SCE_LUA_STRING or style = SCE_LUA_COMMENTLINE then
|
||
|
return -- no completion in strings or comments
|
||
|
end if
|
||
|
|
||
|
calltip_save = calltip_pos
|
||
|
if ssm(SCI_GETCHARAT, pos-1) = '(' then
|
||
|
calltip_pos = pos
|
||
|
pos -= 1
|
||
|
end if
|
||
|
|
||
|
-- use scintilla's code completion
|
||
|
text = get_edit_text()
|
||
|
word = word_pos(text, pos)
|
||
|
if length(word) < 4 or length(word[1]) = 0 then
|
||
|
calltip_pos = calltip_save
|
||
|
return
|
||
|
end if
|
||
|
pos = word[3]
|
||
|
end_pos = word[4]
|
||
|
name_space = word[2]
|
||
|
word = word[1]
|
||
|
|
||
|
decls = get_subroutine_arguments(parse(text, file_name), word, name_space)
|
||
|
if length(decls) then
|
||
|
decls = decls[$] -- overloaded? use the last one
|
||
|
if calltip_save != -1 then
|
||
|
calltip_stack &= {calltip_save, calltip_args, calltip_text}
|
||
|
end if
|
||
|
text = decls[1] & " " & decls[2] & "("
|
||
|
calltip_args = {}
|
||
|
for i = 3 to length(decls) by 3 do
|
||
|
if i != 3 then text &= ", " end if
|
||
|
if decls[i+2] then text &= "[" end if
|
||
|
calltip_args &= {{length(text), 0}}
|
||
|
text &= decls[i] & " " & decls[i+1]
|
||
|
calltip_args[$][2] = length(text)
|
||
|
if decls[i+2] then text &= "]" end if
|
||
|
end for
|
||
|
text &= ")"
|
||
|
--puts(1, text & "\n")
|
||
|
calltip_text = text
|
||
|
ssm(SCI_CALLTIPSHOW, pos, text)
|
||
|
if length(calltip_args) then
|
||
|
--ssm(SCI_CALLTIPSETHLT, calltip_args[1][1], calltip_args[1][2])
|
||
|
calltip_pos = end_pos+1
|
||
|
else
|
||
|
calltip_pos = -1 -- no arguments, no need to update
|
||
|
end if
|
||
|
return
|
||
|
end if
|
||
|
|
||
|
-- decl not found, search includes instead
|
||
|
decls = suggest_includes(word, name_space)
|
||
|
text = ""
|
||
|
for i = 1 to length(decls) by 2 do
|
||
|
if length(decls[i]) >= length(word) and equal(decls[i][1..length(word)], word) then
|
||
|
if length(text) then
|
||
|
text &= '\n'
|
||
|
end if
|
||
|
text &= sreplace(decls[i], " --", "( --")
|
||
|
end if
|
||
|
end for
|
||
|
if length(text) then
|
||
|
ssm(SCI_GOTOPOS, end_pos+1)
|
||
|
ssm(SCI_AUTOCSHOW, length(word)+1, text)
|
||
|
end if
|
||
|
end procedure
|
||
|
|
||
|
|
||
|
procedure update_subroutine_arguments()
|
||
|
sequence text
|
||
|
integer pos, arg, ch
|
||
|
|
||
|
pos = get_pos()
|
||
|
|
||
|
ch = ssm(SCI_GETCHARAT, pos-1, 0)
|
||
|
if ch != ',' and ch != '(' and ch != ')' and ssm(SCI_GETCHARAT, pos, 0) != ',' and last_deleted_char != ',' then
|
||
|
-- this isn't reliable; backspace over comma, or delete selection containing comma, etc.
|
||
|
return
|
||
|
end if
|
||
|
|
||
|
while 1 do
|
||
|
|
||
|
while calltip_pos = -1 or pos < calltip_pos do
|
||
|
if length(calltip_stack) = 0 then
|
||
|
calltip_pos = -1
|
||
|
return
|
||
|
end if
|
||
|
calltip_pos = calltip_stack[$-2]
|
||
|
calltip_args = calltip_stack[$-1]
|
||
|
calltip_text = calltip_stack[$]
|
||
|
ssm(SCI_CALLTIPSHOW, calltip_pos, calltip_text)
|
||
|
calltip_stack = calltip_stack[1..$-3]
|
||
|
end while
|
||
|
|
||
|
-- get the text from after '(' up to the cursor
|
||
|
text = repeat(0, pos - calltip_pos)
|
||
|
for i = 1 to length(text) do
|
||
|
text[i] = ssm(SCI_GETCHARAT, calltip_pos+i-1)
|
||
|
end for
|
||
|
|
||
|
arg = parse_argument_position(text)
|
||
|
if arg = 0 then
|
||
|
-- parsed closing ')'
|
||
|
ssm(SCI_CALLTIPCANCEL)
|
||
|
calltip_pos = -1
|
||
|
elsif arg > length(calltip_args) then
|
||
|
-- parsed too many arguments
|
||
|
ssm(SCI_CALLTIPSETHLT, 0, 0)
|
||
|
exit
|
||
|
else
|
||
|
-- highlight argument at cursor position
|
||
|
ssm(SCI_CALLTIPSETHLT, calltip_args[arg][1], calltip_args[arg][2])
|
||
|
exit
|
||
|
end if
|
||
|
|
||
|
end while
|
||
|
end procedure
|
||
|
|
||
|
|
||
|
function ltrim(sequence s)
|
||
|
for i = 1 to length(s) do
|
||
|
if not find(s[i], " \t\n\r") then
|
||
|
return s[i..$]
|
||
|
end if
|
||
|
end for
|
||
|
return ""
|
||
|
end function
|
||
|
|
||
|
function rtrim(sequence s)
|
||
|
for i = length(s) to 1 by -1 do
|
||
|
if not find(s[i], " \t\n\r") then
|
||
|
return s[1..i]
|
||
|
end if
|
||
|
end for
|
||
|
return ""
|
||
|
end function
|
||
|
|
||
|
|
||
|
-- expand "if " to "if then\n\nend if", etc.
|
||
|
procedure auto_expand()
|
||
|
sequence text, indent, indent_str
|
||
|
integer pos, end_pos
|
||
|
atom junk
|
||
|
|
||
|
if length(expansions) = 0 then
|
||
|
return
|
||
|
end if
|
||
|
|
||
|
-- make sure the current position is at the end of the line
|
||
|
pos = get_pos()
|
||
|
end_pos = get_line_end_position(-1)
|
||
|
if pos != end_pos then return end if
|
||
|
|
||
|
-- save the indentation and trim the line
|
||
|
indent = get_line(-1)
|
||
|
text = ltrim(indent)
|
||
|
indent = "\n" & indent[1..$-length(text)]
|
||
|
text = rtrim(text)
|
||
|
|
||
|
-- try the expansions and get the text to insert
|
||
|
for i = 1 to length(expansions) do
|
||
|
if integer(expansions[i][1]) then
|
||
|
-- try removing "global", "public", "export"
|
||
|
for k = 2 to length(expansions[i]) do
|
||
|
if match(expansions[i][k], text) = 1 then
|
||
|
text = ltrim(text[length(expansions[i][k])..$])
|
||
|
exit
|
||
|
end if
|
||
|
end for
|
||
|
elsif equal(text, expansions[i][1]) then
|
||
|
text = expansions[i][2..$]
|
||
|
insert_chars = reverse(text[1])
|
||
|
exit
|
||
|
elsif i = length(expansions) then
|
||
|
return
|
||
|
end if
|
||
|
end for
|
||
|
|
||
|
indent_str = repeat(' ', ssm(SCI_GETINDENT))
|
||
|
if length(text) >= 3 then
|
||
|
indent_str &= indent & text[3]
|
||
|
end if
|
||
|
text = text[1] & text[2] & indent & indent_str
|
||
|
|
||
|
-- save the line for auto_indent()
|
||
|
expand_line = ssm(SCI_LINEFROMPOSITION, pos)
|
||
|
|
||
|
-- insert the text and restore cursor position
|
||
|
ssm(SCI_INSERTTEXT, pos, text)
|
||
|
end procedure
|
||
|
|
||
|
|
||
|
procedure do_auto_indent()
|
||
|
integer line, pos, end_pos
|
||
|
sequence indent
|
||
|
|
||
|
-- get the previous line and get the indentation
|
||
|
pos = get_pos()
|
||
|
line = ssm(SCI_LINEFROMPOSITION, pos) - 1
|
||
|
end_pos = get_line_end_position(line)
|
||
|
|
||
|
if line = expand_line then
|
||
|
-- delete the newline character and go to end of the next line
|
||
|
ssm(SCI_DELETERANGE, end_pos, pos - end_pos)
|
||
|
end_pos = get_line_end_position(line + 1)
|
||
|
ssm(SCI_GOTOPOS, end_pos)
|
||
|
expand_line = -1
|
||
|
insert_chars = {}
|
||
|
return
|
||
|
end if
|
||
|
expand_line = -1
|
||
|
|
||
|
-- get the indentation of the previous line, and remove newline
|
||
|
indent = get_line(line)
|
||
|
for i = length(indent)-length(ltrim(indent)) to 0 by -1 do
|
||
|
if i = 0 or (indent[i] != '\n' and indent[i] != '\r') then
|
||
|
indent = indent[1..i]
|
||
|
exit
|
||
|
end if
|
||
|
end for
|
||
|
|
||
|
-- insert the indentation
|
||
|
ssm(SCI_ADDTEXT, length(indent), indent)
|
||
|
end procedure
|
||
|
|
||
|
|
||
|
procedure do_brace_highlight(atom hedit)
|
||
|
integer pos, brace, ch
|
||
|
brace = -1
|
||
|
pos = get_pos()-1
|
||
|
if find(ssm(SCI_GETCHARAT, pos, 0), "{}()[]") then
|
||
|
brace = ssm(SCI_BRACEMATCH, pos, 0)
|
||
|
end if
|
||
|
if brace = -1 then
|
||
|
pos += 1
|
||
|
if find(ssm(SCI_GETCHARAT, pos, 0), "{}()[]") then
|
||
|
brace = ssm(SCI_BRACEMATCH, pos, 0)
|
||
|
end if
|
||
|
if brace = -1 then
|
||
|
pos = -1
|
||
|
end if
|
||
|
end if
|
||
|
brace = ssm(SCI_BRACEHIGHLIGHT, pos, brace)
|
||
|
end procedure
|
||
|
-- FIXME: this has a problem with brace chars within strings, for ex: {1, "}{", 2}
|
||
|
|
||
|
|
||
|
procedure auto_complete_selection(integer pos, sequence text)
|
||
|
integer inc, len, insert_line, arg, ns
|
||
|
sequence line
|
||
|
|
||
|
-- insert include statement if completion contains it
|
||
|
inc = match(" --include", text)
|
||
|
|
||
|
ns = find(':', text)
|
||
|
if ns and ssm(SCI_GETCHARAT, pos-1) = ':' then
|
||
|
line = ""
|
||
|
while length(line) < ns do
|
||
|
line = ssm(SCI_GETCHARAT, pos-length(line)-2) & line
|
||
|
if equal(line, text[1..length(line)]) then
|
||
|
ssm(SCI_DELETERANGE, pos-length(line)-1, length(line)+1)
|
||
|
exit
|
||
|
end if
|
||
|
end while
|
||
|
if not inc then
|
||
|
ssm(SCI_ADDTEXT, length(text), text)
|
||
|
ssm(SCI_AUTOCCANCEL, 0, 0)
|
||
|
end if
|
||
|
end if
|
||
|
|
||
|
if inc then
|
||
|
ssm(SCI_AUTOCCANCEL, 0, 0)
|
||
|
|
||
|
len = get_pos() - pos
|
||
|
|
||
|
arg = text[inc-1] = '('
|
||
|
if arg then
|
||
|
-- delete the existing '(' since we are adding another one
|
||
|
len -= 1
|
||
|
ssm(SCI_DELETERANGE, pos + len, 1)
|
||
|
end if
|
||
|
|
||
|
if len < 0 then
|
||
|
len = 0
|
||
|
end if
|
||
|
-- add in the selected text
|
||
|
if len+1 <= inc then
|
||
|
ssm(SCI_ADDTEXT, inc-1-len, text[len+1..inc])
|
||
|
end if
|
||
|
text = text[inc+3..$] & "\n"
|
||
|
|
||
|
-- search first few lines for include statements
|
||
|
insert_line = -1
|
||
|
for i = 0 to 100 do
|
||
|
line = ltrim(get_line(i))
|
||
|
if length(line) >= 8 and equal(line[1..8], "include ") then
|
||
|
insert_line = i+1
|
||
|
elsif insert_line != -1 then
|
||
|
exit
|
||
|
end if
|
||
|
end for
|
||
|
if insert_line = -1 then
|
||
|
-- insert after consecutive comment lines
|
||
|
insert_line = 0
|
||
|
for i = 0 to 100 do
|
||
|
line = ltrim(get_line(i))
|
||
|
if length(line) >= 2 and line[1]='-' and line[2]='-' then
|
||
|
insert_line = i+1
|
||
|
else
|
||
|
exit
|
||
|
end if
|
||
|
end for
|
||
|
end if
|
||
|
inc = ssm(SCI_POSITIONFROMLINE, insert_line, 0)
|
||
|
if inc = -1 or inc > pos then
|
||
|
inc = 0
|
||
|
end if
|
||
|
ssm(SCI_INSERTTEXT, inc, text)
|
||
|
if arg then
|
||
|
view_subroutine_arguments()
|
||
|
end if
|
||
|
end if
|
||
|
|
||
|
end procedure
|
||
|
|
||
|
-- insert closing character when user types ( [ { ' "
|
||
|
procedure insert_pair()
|
||
|
integer pos, style, ch
|
||
|
|
||
|
if not complete_braces then return end if
|
||
|
|
||
|
pos = get_pos()-1
|
||
|
|
||
|
-- avoid inside strings and comments
|
||
|
if pos != get_line_start_position(-1) then
|
||
|
style = ssm(SCI_GETSTYLEAT, pos-1)
|
||
|
if style = SCE_LUA_COMMENTLINE or
|
||
|
(style = SCE_LUA_STRING and
|
||
|
style = ssm(SCI_GETSTYLEAT, pos+1)) then
|
||
|
return
|
||
|
end if
|
||
|
end if
|
||
|
|
||
|
-- avoid inside words or numbers
|
||
|
for i = pos+1 to get_line_end_position(-1) do
|
||
|
ch = ssm(SCI_GETCHARAT, i)
|
||
|
style = ssm(SCI_GETSTYLEAT, i)
|
||
|
if find(ch, ",)}]\r\n+-*/=!<>#&\0") or style = SCE_LUA_WORD then
|
||
|
exit
|
||
|
elsif ch != ' ' and ch != '\t' then
|
||
|
return
|
||
|
end if
|
||
|
end for
|
||
|
ch = ssm(SCI_GETCHARAT, pos, 0)
|
||
|
if ch = '(' then
|
||
|
ch = ')'
|
||
|
elsif ch = '{' then
|
||
|
ch = '}'
|
||
|
elsif ch = '[' then
|
||
|
ch = ']'
|
||
|
end if
|
||
|
ssm(SCI_INSERTTEXT, pos+1, {ch})
|
||
|
insert_chars &= ch
|
||
|
end procedure
|
||
|
|
||
|
-- remove the characters inserted by insert_pair(), won't work for ' " tho
|
||
|
procedure delete_pair()
|
||
|
if length(insert_chars) = 0 then
|
||
|
return
|
||
|
end if
|
||
|
if insert_chars[$] = last_deleted_char then
|
||
|
insert_chars = insert_chars[1..$-1]
|
||
|
elsif (last_deleted_char = '(' and insert_chars[$] = ')') or
|
||
|
(last_deleted_char = '[' and insert_chars[$] = ']') or
|
||
|
(last_deleted_char = '{' and insert_chars[$] = '}') then
|
||
|
ssm(SCI_DELETERANGE, get_pos(), 1)
|
||
|
insert_chars = insert_chars[1..$-1]
|
||
|
end if
|
||
|
end procedure
|
||
|
|
||
|
-- open file(s) from a drag and drop operation
|
||
|
procedure open_uri(sequence uri)
|
||
|
uri = split(uri, "\r\n")
|
||
|
for i = 1 to length(uri) do
|
||
|
if match("file://", uri[i]) = 1 then
|
||
|
open_file(uri[i][8..$], 0)
|
||
|
end if
|
||
|
end for
|
||
|
end procedure
|
||
|
|
||
|
-- toggle the comment at the start of each line in selection
|
||
|
global procedure toggle_comment()
|
||
|
integer
|
||
|
pos = ssm(SCI_GETCURRENTPOS),
|
||
|
anchor = ssm(SCI_GETANCHOR),
|
||
|
line_pos = ssm(SCI_LINEFROMPOSITION, pos),
|
||
|
line_anchor = ssm(SCI_LINEFROMPOSITION, anchor),
|
||
|
col_pos = pos - ssm(SCI_POSITIONFROMLINE, line_pos),
|
||
|
col_anchor = anchor - ssm(SCI_POSITIONFROMLINE, line_anchor),
|
||
|
line_start = ssm(SCI_LINEFROMPOSITION, ssm(SCI_GETSELECTIONSTART)),
|
||
|
line_end = ssm(SCI_LINEFROMPOSITION, ssm(SCI_GETSELECTIONEND)-1)
|
||
|
integer uncomment = 1
|
||
|
if line_end < line_start then
|
||
|
line_end = line_start
|
||
|
end if
|
||
|
-- check to see if all lines are commented
|
||
|
for i = line_start to line_end do
|
||
|
pos = ssm(SCI_POSITIONFROMLINE, i)
|
||
|
if ssm(SCI_GETCHARAT, pos) != '-' or
|
||
|
ssm(SCI_GETCHARAT, pos+1) != '-' then
|
||
|
uncomment = 0 -- non comment detected
|
||
|
exit
|
||
|
end if
|
||
|
end for
|
||
|
-- insert/remove comment markers
|
||
|
ssm(SCI_BEGINUNDOACTION)
|
||
|
for i = line_start to line_end do
|
||
|
pos = ssm(SCI_POSITIONFROMLINE, i)
|
||
|
if uncomment then
|
||
|
ssm(SCI_DELETERANGE, pos, 2)
|
||
|
else
|
||
|
ssm(SCI_INSERTTEXT, pos, "--")
|
||
|
end if
|
||
|
end for
|
||
|
ssm(SCI_ENDUNDOACTION)
|
||
|
-- adjust the selection to be the same column as it was before
|
||
|
pos = ssm(SCI_POSITIONFROMLINE, line_pos) + col_pos
|
||
|
anchor = ssm(SCI_POSITIONFROMLINE, line_anchor) + col_anchor
|
||
|
if col_pos != 0 then
|
||
|
pos -= uncomment*4-2
|
||
|
end if
|
||
|
if col_anchor != 0 then
|
||
|
anchor -= uncomment*4-2
|
||
|
end if
|
||
|
ssm(SCI_SETSEL, anchor, pos)
|
||
|
end procedure
|
||
|
|
||
|
-------------------------------------------------------------------
|
||
|
-- eu.cfg handling
|
||
|
-------------------------------------------------------------------
|
||
|
|
||
|
-- returns a list of interpreters that exist on disk
|
||
|
global function get_interpreters()
|
||
|
sequence paths, try, exe, bin, result = {}
|
||
|
integer index
|
||
|
|
||
|
if find(fileext(file_name), {"ew","exw"}) then
|
||
|
bin = {"euiw", "eui", "exw", "ex"}
|
||
|
else
|
||
|
bin = {"eui", "euiw", "ex", "exw"}
|
||
|
end if
|
||
|
ifdef UNIX then
|
||
|
bin = append(bin, "exu")
|
||
|
end ifdef
|
||
|
paths = parse_eu_cfg(dirname(file_name) & SLASH & "eu.cfg")
|
||
|
paths &= include_search_paths -- fallback to running interpreter
|
||
|
for i = 1 to length(paths) do
|
||
|
try = paths[i]
|
||
|
if try[$] = SLASH then
|
||
|
try = try[1..$-1]
|
||
|
end if
|
||
|
for j = 1 to length(bin) do
|
||
|
exe = try & join_path({"..", "bin", bin[j]})
|
||
|
ifdef WINDOWS then
|
||
|
exe &= ".exe"
|
||
|
end ifdef
|
||
|
exe = canonical_path(exe)
|
||
|
if not find(exe, result) and file_exists(exe) then
|
||
|
result = append(result, exe)
|
||
|
end if
|
||
|
end for
|
||
|
end for
|
||
|
if length(interpreter) and not find(interpreter, result) then
|
||
|
result = prepend(result, interpreter)
|
||
|
end if
|
||
|
return result
|
||
|
end function
|
||
|
|
||
|
-- if bin="" returns an interpreter from one of these locations:
|
||
|
-- interpreter global variable if set
|
||
|
-- some interpreter from the paths in eu.cfg
|
||
|
-- the running interpreter's include_paths
|
||
|
-- if bin is "eubind" "eushroud" or "euc" then use the same search
|
||
|
-- paths as above to locate it
|
||
|
global function get_eu_bin(sequence bin)
|
||
|
sequence paths, try, exe
|
||
|
|
||
|
if length(bin) = 0 then
|
||
|
if length(interpreter) != 0 then
|
||
|
return interpreter
|
||
|
end if
|
||
|
if find(fileext(file_name), {"ew","exw"}) then
|
||
|
bin = {"euiw", "eui", "exw", "ex"}
|
||
|
else
|
||
|
bin = {"eui", "euiw", "ex", "exw"}
|
||
|
end if
|
||
|
ifdef UNIX then
|
||
|
bin = append(bin, "exu")
|
||
|
end ifdef
|
||
|
else
|
||
|
bin = {bin}
|
||
|
end if
|
||
|
|
||
|
paths = parse_eu_cfg(dirname(file_name) & SLASH & "eu.cfg")
|
||
|
paths &= include_search_paths -- fallback to running interpreter
|
||
|
try = dirname(interpreter)
|
||
|
if length(try) then
|
||
|
paths = prepend(paths, try)
|
||
|
end if
|
||
|
for i = 1 to length(paths) do
|
||
|
try = paths[i]
|
||
|
if try[$] = SLASH then
|
||
|
try = try[1..$-1]
|
||
|
end if
|
||
|
for j = 1 to length(bin) do
|
||
|
exe = try & join_path({"..", "bin", bin[j]})
|
||
|
ifdef WINDOWS then
|
||
|
exe &= ".exe"
|
||
|
end ifdef
|
||
|
exe = canonical_path(exe)
|
||
|
if file_exists(exe) then
|
||
|
return exe
|
||
|
end if
|
||
|
end for
|
||
|
end for
|
||
|
return bin[1]
|
||
|
end function
|
||
|
|
||
|
-- returns text in quotes if it contains spaces
|
||
|
global function quote_spaces(sequence text)
|
||
|
if find(' ', text) then
|
||
|
for i = length(text) to 1 by -1 do
|
||
|
if text[i] = '"' or text[i] = '\\' then
|
||
|
text = text[1..i-1] & '\\' & text[i..$]
|
||
|
end if
|
||
|
end for
|
||
|
return '"' & text & '"'
|
||
|
end if
|
||
|
return text
|
||
|
end function
|
||
|
|
||
|
|
||
|
-------------------------------------------------------------------
|
||
|
-- scintilla editor notifications
|
||
|
-------------------------------------------------------------------
|
||
|
|
||
|
procedure log_notification(atom notification)
|
||
|
integer code, pos, ch, modifiers
|
||
|
code = peek4u(notification+8)
|
||
|
pos = peek4u(notification+12)
|
||
|
if code = SCN_STYLENEEDED then
|
||
|
puts(1, "SCN_STYLENEEDED\n")
|
||
|
elsif code = SCN_CHARADDED then
|
||
|
ch = peek4s(notification+16)
|
||
|
printf(1, "SCN_CHARADDED ch=%d '%s'\n", {ch, {ch}})
|
||
|
elsif code = SCN_SAVEPOINTREACHED then
|
||
|
puts(1, "SCN_SAVEPOINTREACHED\n")
|
||
|
elsif code = SCN_SAVEPOINTLEFT then
|
||
|
puts(1, "SCN_SAVEPOINTLEFT\n")
|
||
|
elsif code = SCN_MODIFYATTEMPTRO then
|
||
|
puts(1, "SCN_MODIFYATTEMPTRO\n")
|
||
|
elsif code = SCN_KEY then
|
||
|
ch = peek4s(notification+16)
|
||
|
modifiers = peek4s(notification+20)
|
||
|
printf(1, "SCN_KEY ch=%d modifiers=#%x\n", {ch, modifiers})
|
||
|
elsif code = SCN_DOUBLECLICK then
|
||
|
puts(1, "SCN_DOUBLECLICK\n")
|
||
|
elsif code = SCN_UPDATEUI then
|
||
|
printf(1, "SCN_UPDATEUI updated=#%x\n", {peek4s(notification+88)})
|
||
|
elsif code = SCN_MODIFIED then
|
||
|
puts(1, "SCN_MODIFIED\n")
|
||
|
elsif code = SCN_MACRORECORD then
|
||
|
puts(1, "SCN_MACRORECORD\n")
|
||
|
elsif code = SCN_MARGINCLICK then
|
||
|
puts(1, "SCN_MARGINCLICK\n")
|
||
|
elsif code = SCN_NEEDSHOWN then
|
||
|
puts(1, "SCN_NEEDSHOWN\n")
|
||
|
elsif code = SCN_PAINTED then
|
||
|
--gets sent after each caret blink
|
||
|
--puts(1, "SCN_PAINTED\n")
|
||
|
elsif code = SCN_USERLISTSELECTION then
|
||
|
puts(1, "SCN_USERLISTSELECTION\n")
|
||
|
elsif code = SCN_URIDROPPED then
|
||
|
puts(1, "SCN_URIDROPPED\n")
|
||
|
elsif code = SCN_DWELLSTART then
|
||
|
puts(1, "SCN_DWELLSTART\n")
|
||
|
elsif code = SCN_DWELLEND then
|
||
|
puts(1, "SCN_DWELLEND\n")
|
||
|
elsif code = SCN_ZOOM then
|
||
|
puts(1, "SCN_ZOOM\n")
|
||
|
elsif code = SCN_HOTSPOTCLICK then
|
||
|
puts(1, "SCN_HOTSPOTCLICK\n")
|
||
|
elsif code = SCN_HOTSPOTDOUBLECLICK then
|
||
|
puts(1, "SCN_HOTSPOTDOUBLECLICK\n")
|
||
|
elsif code = SCN_HOTSPOTRELEASECLICK then
|
||
|
puts(1, "SCN_HOTSPOTRELEASECLICK\n")
|
||
|
elsif code = SCN_INDICATORCLICK then
|
||
|
puts(1, "SCN_INDICATORCLICK\n")
|
||
|
elsif code = SCN_INDICATORRELEASE then
|
||
|
puts(1, "SCN_INDICATORRELEASE\n")
|
||
|
elsif code = SCN_CALLTIPCLICK then
|
||
|
puts(1, "SCN_CALLTIPCLICK\n")
|
||
|
elsif code = SCN_AUTOCSELECTION then
|
||
|
puts(1, "SCN_AUTOCSELECTION\n")
|
||
|
elsif code = SCN_AUTOCCANCELLED then
|
||
|
puts(1, "SCN_AUTOCCANCELLED\n")
|
||
|
elsif code = SCN_AUTOCCHARDELETED then
|
||
|
puts(1, "SCN_AUTOCCHARDELETED\n")
|
||
|
elsif code = SCN_FOCUSIN then
|
||
|
puts(1, "SCN_FOCUSIN\n")
|
||
|
elsif code = SCN_FOCUSOUT then
|
||
|
puts(1, "SCN_FOCUSOUT\n")
|
||
|
end if
|
||
|
end procedure
|
||
|
|
||
|
ifdef BITS64 then
|
||
|
constant
|
||
|
NOTIFICATION_CODE = 16,
|
||
|
NOTIFICATION_POS = 24,
|
||
|
NOTIFICATION_CH = 28,
|
||
|
NOTIFICATION_MODIFIERS = 32,
|
||
|
NOTIFICATION_MODIFICATIONTYPE = 36,
|
||
|
NOTIFICATION_TEXT = 40,
|
||
|
NOTIFICATION_LENGTH = 48,
|
||
|
NOTIFICATION_UPDATED = 116
|
||
|
elsedef
|
||
|
constant
|
||
|
NOTIFICATION_CODE = 8,
|
||
|
NOTIFICATION_POS = 12,
|
||
|
NOTIFICATION_CH = 16,
|
||
|
NOTIFICATION_MODIFIERS = 20,
|
||
|
NOTIFICATION_MODIFICATIONTYPE = 24,
|
||
|
NOTIFICATION_TEXT = 28,
|
||
|
NOTIFICATION_LENGTH = 32,
|
||
|
NOTIFICATION_UPDATED = 88
|
||
|
end ifdef
|
||
|
|
||
|
function notification_text(atom notification)
|
||
|
ifdef BITS64 then
|
||
|
return peek_string(peek8u(notification+NOTIFICATION_TEXT))
|
||
|
elsedef
|
||
|
return peek_string(peek4u(notification+NOTIFICATION_TEXT))
|
||
|
end ifdef
|
||
|
end function
|
||
|
|
||
|
global function sci_notify(atom hedit, atom data, atom notification, atom userdata)
|
||
|
integer code, pos, ch, modifiers, updated, len
|
||
|
|
||
|
if notification = 0 then return 0 end if
|
||
|
--log_notification(notification)
|
||
|
code = peek4u(notification+NOTIFICATION_CODE)
|
||
|
if code = SCN_UPDATEUI then
|
||
|
updated = peek4u(notification+NOTIFICATION_UPDATED)
|
||
|
if ssm(SCI_CALLTIPACTIVE) then
|
||
|
update_subroutine_arguments()
|
||
|
end if
|
||
|
if and_bits(updated, SC_UPDATE_SELECTION+SC_UPDATE_CONTENT) = SC_UPDATE_SELECTION then
|
||
|
-- selection moved and content was not changed
|
||
|
insert_chars = ""
|
||
|
elsif last_deleted_char then
|
||
|
delete_pair()
|
||
|
last_deleted_char = 0
|
||
|
end if
|
||
|
if and_bits(updated, SC_UPDATE_SELECTION) then
|
||
|
update_status()
|
||
|
end if
|
||
|
|
||
|
do_brace_highlight(hedit)
|
||
|
|
||
|
elsif code = SCN_SAVEPOINTREACHED or code = SCN_SAVEPOINTLEFT then
|
||
|
modified = (code = SCN_SAVEPOINTLEFT)
|
||
|
update_tab_name()
|
||
|
|
||
|
elsif code = SCN_KEY then
|
||
|
ch = peek4s(notification+NOTIFICATION_CH)
|
||
|
modifiers = peek4s(notification+NOTIFICATION_MODIFIERS)
|
||
|
-- on OSX X11, META and SHIFT are the only modifiers we receive
|
||
|
|
||
|
if ch = 'Z' and and_bits(modifiers, SCMOD_CTRL+SCMOD_META) then
|
||
|
if and_bits(modifiers, SCMOD_SHIFT) then
|
||
|
ssm(SCI_REDO, 0, 0)
|
||
|
else
|
||
|
ssm(SCI_UNDO, 0, 0)
|
||
|
end if
|
||
|
|
||
|
elsif ch >= '1' and ch <= '9' and and_bits(modifiers, SCMOD_ALT+SCMOD_META) then
|
||
|
select_tab(ch - '0')
|
||
|
|
||
|
elsif ch < 128 then
|
||
|
--printf(1, "SCN_KEY ch=%d '%s' modifiers=%d\n", {ch, {ch}, modifiers})
|
||
|
else
|
||
|
--printf(1, "SCN_KEY ch=#%x modifiers=%d\n", {ch, modifiers})
|
||
|
end if
|
||
|
|
||
|
elsif code = SCN_CHARADDED then
|
||
|
ch = peek4s(notification+NOTIFICATION_CH)
|
||
|
|
||
|
if length(insert_chars) and ch = insert_chars[$] then
|
||
|
-- the user retyped the insert character, so delete it
|
||
|
ssm(SCI_DELETERANGE, get_pos(), 1)
|
||
|
-- the UPDATEUI will remove the insert_chars[$]
|
||
|
elsif ch = ':' and auto_namespace then
|
||
|
view_completions()
|
||
|
elsif ch = ' ' and complete_statements then
|
||
|
auto_expand()
|
||
|
elsif ch = '\n' and auto_indent then
|
||
|
do_auto_indent()
|
||
|
elsif ch = '(' then
|
||
|
-- check for displaying subroutine arguments
|
||
|
if complete_braces then
|
||
|
insert_pair()
|
||
|
end if
|
||
|
if auto_arguments then
|
||
|
view_subroutine_arguments()
|
||
|
end if
|
||
|
elsif ch = '{' or ch = '[' and complete_braces then
|
||
|
insert_pair()
|
||
|
elsif ch = '"' or ch = '\'' and complete_braces then
|
||
|
insert_pair()
|
||
|
end if
|
||
|
|
||
|
elsif code = SCN_AUTOCSELECTION then
|
||
|
-- check for "--include" in selection, then add include statement near top of file
|
||
|
-- or after the first non-commented line, or ideally with other includes
|
||
|
pos = peek4s(notification+NOTIFICATION_POS)
|
||
|
auto_complete_selection(pos, notification_text(notification))
|
||
|
|
||
|
elsif code = SCN_MODIFIED then
|
||
|
modifiers = peek4u(notification+NOTIFICATION_MODIFICATIONTYPE)
|
||
|
if and_bits(modifiers, SC_MOD_BEFOREDELETE) then
|
||
|
pos = peek4s(notification+NOTIFICATION_POS)
|
||
|
len = peek4u(notification+NOTIFICATION_LENGTH)
|
||
|
if len = 1 then
|
||
|
last_deleted_char = ssm(SCI_GETCHARAT, pos)
|
||
|
end if
|
||
|
end if
|
||
|
if auto_indicator and ssm(SCI_GETLEXER) = SCLEX_LUA and
|
||
|
and_bits(modifiers, SC_MOD_INSERTTEXT + SC_MOD_DELETETEXT) then
|
||
|
change_time = time() + .5
|
||
|
end if
|
||
|
|
||
|
elsif code = SCN_URIDROPPED then
|
||
|
open_uri(notification_text(notification))
|
||
|
|
||
|
elsif code = SCN_DWELLSTART then
|
||
|
pos = peek4s(notification+NOTIFICATION_POS)
|
||
|
if change_time = 0 then
|
||
|
dwell_error(pos)
|
||
|
end if
|
||
|
|
||
|
elsif code = SCN_DWELLEND then
|
||
|
if calltip_dwell then
|
||
|
ssm(SCI_CALLTIPCANCEL)
|
||
|
calltip_dwell = 0
|
||
|
end if
|
||
|
|
||
|
elsif code = SCN_PAINTED then
|
||
|
-- could run some background processing during painted, every time cursor blinks
|
||
|
|
||
|
if auto_indicator and change_time and change_time <= time() then
|
||
|
do_error_indicators()
|
||
|
change_time = 0
|
||
|
end if
|
||
|
end if
|
||
|
return 0
|
||
|
end function
|