Compare commits

..

102 Commits
0.30 ... 0.32

Author SHA1 Message Date
Paul Kulchenko
8419287316 Updated changelog for v0.32 2012-09-03 16:53:50 -07:00
Paul Kulchenko
27d1d159f6 Added configuration option for specifying entry points for moai projects (moai.entrypoints). 2012-09-02 21:21:05 -07:00
Paul Kulchenko
491d37038a Added changelog. 2012-09-02 19:58:16 -07:00
Paul Kulchenko
67eee4f9ef Corrected an image with Lua files used in the project tree 2012-09-02 14:23:40 -07:00
Paul Kulchenko
552a7373ca Switched moai to starting debugging right away without stopping on the first line. 2012-09-01 22:54:06 -07:00
Paul Kulchenko
376a25dfdd Added option to start debugging without stopping on the first line. 2012-09-01 22:53:38 -07:00
Paul Kulchenko
7945a09811 Fixed an issue with debugger not activating files with relative path information 2012-08-31 16:20:56 -07:00
Paul Kulchenko
327f650121 Fixed 'break' command to work after coming from debugger calls (like on()) 2012-08-31 15:58:10 -07:00
Paul Kulchenko
9bceb449e8 Added an IO filter to fix an issue with 0d0d0a line endings on Windows.
Scintilla doesn't strictly follow SetEOLMode setting and accepts both 0d
and 0d0a (and possibly 0a too) as line endings on Windows. Unfortunately,
the standard Lua interpreter does the right thing and only recognizes 0d0a
as the valid marker. This means line numbers are going to be different in
two cases, which creates a problem for breakpoints during debugging.
2012-08-31 15:48:37 -07:00
Paul Kulchenko
4278c25c60 Fixed an issue with highlighting selected item in the project tree.
An attempt to unhighlight the current item (that could have been
removed from the tree when the project directory is changed) led to
a crash of the application on OSX (but not on Windows).
2012-08-31 15:13:33 -07:00
Paul Kulchenko
7f47506eae Upgraded to mobdebug v0.489 to add support for debugging moai callbacks 2012-08-30 12:20:44 -07:00
Paul Kulchenko
b0b137eaf1 Added refresh of Stack and Watch windows to show updated values after executing a statement in remote shell 2012-08-30 12:13:32 -07:00
Paul Kulchenko
d1d29ced43 Added display of complex values on multiple lines in shell with '=' 2012-08-30 11:40:47 -07:00
Paul Kulchenko
2795d4d9ce Added rockspec to the list of extensions for lua (fixes #37) 2012-08-29 14:17:56 -07:00
Paul Kulchenko
02845f2e87 Added a check to avoid evaluating keywords in tooltip 2012-08-29 11:54:54 -07:00
Paul Kulchenko
ec46531c55 Merge branch 'master' of git://estrelaeditor.git.sourceforge.net/gitroot/estrelaeditor/estrelaeditor 2012-08-28 23:00:22 -07:00
Paul Kulchenko
9895f06f97 Added correctly stripped version of wx.dll (used --strip-unneded instead of --strip-all) 2012-08-28 22:39:31 -07:00
Paul Kulchenko
a67feb86aa Added current interpreter to the status bar; adding closing debugger when the interpreter is changed 2012-08-28 21:57:52 -07:00
Paul Kulchenko
6b990b652c Updated status bar style to make it consistent across platforms 2012-08-28 21:56:21 -07:00
Paul Kulchenko
7a2326cc9e Fixed evaluation of foo:bar in tooltip (now evaluates as foo.bar) 2012-08-28 21:26:59 -07:00
crazybutcher
e129f486d9 Merge remote-tracking branch 'zbstudio/master'
Conflicts:
	bin/lua51.dll
2012-08-25 15:48:54 +02:00
Paul Kulchenko
c09d9fc143 Updated wx.dll to include missing dependencies: libstdc++-6.dll and libgcc_s_dw2-1.dll (fixes #33) 2012-08-22 22:45:37 -07:00
crazybutcher
52ef014941 updated GLSL to 4.3 status
cg tool: glsl compilation no longer requires a selected word (main is always entry)
2012-08-22 16:53:45 +02:00
Paul Kulchenko
e79fedf764 Added aborting scratchpad processing when an interpreter can't start or report a fatal error 2012-08-20 21:25:34 -07:00
Paul Kulchenko
b7544577df Refactored LUA_PATH/CPATH processing to set it for all interpreters 2012-08-20 21:23:33 -07:00
Paul Kulchenko
53110b3b2f Updated wx.dll to fix scratchpad processing.
Partially reverted wxlua commit r104
(http://wxlua.svn.sourceforge.net/viewvc/wxlua?view=revision&revision=104).
2012-08-20 21:18:54 -07:00
Paul Kulchenko
d6ee3d1278 Added calltip on mouseover for functions during editing and for variables/expressions during debugging 2012-08-20 11:18:15 -07:00
Paul Kulchenko
c0109a26d1 Added a workaround for GetExecutablePath() reporting 'wx.dll' instead of a proper exe name with wxlua 2.8.12.2 on Windows 2012-08-20 10:47:57 -07:00
Paul Kulchenko
2a706f5bf3 Updated test module to use stringified values for comparison 2012-08-20 08:55:49 -07:00
Paul Kulchenko
1f266e04ab Added moai to the manifest 2012-08-19 23:25:13 -07:00
Paul Kulchenko
f45d6f84a3 Changed reporting of program execution time from CPU time to user time 2012-08-18 23:24:53 -07:00
Paul Kulchenko
76b8b7b07b Reassigned hotkeys in the Project menu to minimize conflicts on Mac 2012-08-18 23:22:20 -07:00
Paul Kulchenko
d45f893943 Fixed debugger termination after internal errors 2012-08-18 16:54:14 -07:00
Paul Kulchenko
53e725cf03 Removed .bak files from being replaced in when backup copies are saved 2012-08-18 16:41:12 -07:00
Paul Kulchenko
8a66df19fa Added support for unicode path files on Windows (fixes #30).
Replaced GetCwd() with wx.wxStandardPaths.Get():GetExecutablePath() as the
former doesn't return proper unicode path (at least in wxlua 2.8.12.2).
Replaced io.open with wxFile operations and disabled default error reporting.
Replaced os.rename with wxRenameFile.
Added support for unicode in dofile for Lua (replaced unicode names with
short names using winapi).
Fixed navigation in the Output window to recognize unicode file names.
Upgraded to MobDebug v0.485 to make debugging/breakpoints/step work for
files with unicode paths.
2012-08-17 22:14:27 -07:00
Paul Kulchenko
13be57ae39 Added an option to set path to lua executable 2012-08-16 17:32:43 -07:00
Paul Kulchenko
684150714f Updated love2d interpreter to use the project folder to check for
main.lua.

This allows Run/Debug project with any project file being currently active.
2012-08-11 22:27:41 -07:00
Paul Kulchenko
01e23f448e Fixed activating current file in the project tree on Mac (closes #29) 2012-08-11 22:25:38 -07:00
crazybutcher
036ec3534a modified slightly so ffitoapi can be run standalone 2012-08-11 15:37:51 +02:00
crazybutcher
af57806c69 updated luxinia2's glewgl and added anttweakbar 2012-08-11 15:36:19 +02:00
Paul Kulchenko
a4773563e9 Fixed running scripts with single quotes in path names 2012-08-07 20:10:52 -07:00
Paul Kulchenko
195c463a60 Added error handler to trap and display debugger errors 2012-08-07 19:56:07 -07:00
Paul Kulchenko
8cbf20ae42 Removed explicit path conversions and comparisons 2012-08-07 19:54:36 -07:00
Paul Kulchenko
a11bd6f0d3 Added search in PATH for love2d executable 2012-08-07 18:14:57 -07:00
Paul Kulchenko
1fc12a8a76 Fixed an issue with Run/Debug commands when IDE path includes exclamation mark ('!') 2012-08-07 17:01:26 -07:00
Paul Kulchenko
9a1e681569 Updated moai support to use full path to executable and to search for config.lua 2012-08-07 12:38:08 -07:00
Paul Kulchenko
43083742e6 Updated coroutine debugging to allow stepping through coroutine.resume/.yield calls 2012-08-06 16:40:29 -07:00
Paul Kulchenko
9a5b481189 Changed the call to unhide windows to the async version (ShowWindowAsync) to avoid blocking the IDE when the application doesn't respond 2012-08-05 21:07:22 -07:00
Paul Kulchenko
565f8e74fb Signed zbstudio executable to avoid issues with files not being saved without admin privileges and to remove warning about 'unknown publisher' on windows (fixes #25) 2012-08-05 18:05:17 -07:00
Paul Kulchenko
b1b87e9013 Fixed an issue with the app not starting on those systems that don't have HOME environment variable; fixes #28 2012-08-05 18:00:02 -07:00
Paul Kulchenko
539eddbf9d Fixed an issue with showing/hiding GUI windows that was occasionally causing a runtime error when the window disappears before it is manipulated 2012-08-03 12:43:58 -07:00
Paul Kulchenko
0abcff015e Added moai interpreter 2012-08-02 17:51:32 -07:00
Paul Kulchenko
7bb74b5fb4 Fixed returning proper name for unsaved files in reporting compilation and static analysis results; moved default names to ide.config (fixes #26) 2012-08-01 16:30:35 -07:00
Paul Kulchenko
b9bc6454b4 Added reporting of function name of the form a.b and a:b in static analysis (fixes #27) 2012-08-01 15:49:37 -07:00
Paul Kulchenko
5734455818 Merge branch 'master' of github.com:pkulchenko/ZeroBraneStudio 2012-08-01 15:07:06 -07:00
Paul Kulchenko
e6e0870a11 Merge pull request #24 from Odie/master
Added ability for user to keep their settings file in their home directory
2012-08-01 15:06:07 -07:00
Paul Kulchenko
2c45207436 Fixed pasting text into the Find dialog and project path box on Mac (fixes #22) 2012-08-01 15:02:36 -07:00
Jonathan Shieh
bf09d3748c Added per user settings file.
Users can now move their settings file to ~/.zbs/user.lua
2012-08-01 10:54:40 +08:00
Paul Kulchenko
452f99826e Upgraded to wxlua 2.8.12.2 (wxwidgets 2.8.12; unicode version); added
lua51.dll proxy (fixes #10 and #7)
2012-07-30 23:11:30 -07:00
Paul Kulchenko
bbfc1c3624 Reorganized handling of automcomplete event (to use AddPendingEvent instead of PostEvent) to avoid runtime application error 2012-07-30 23:02:47 -07:00
Paul Kulchenko
429bb24cb4 Upgraded to mobdebug 0.479 to fix bugs with localization of variables during debugging and handling dashes in paths; added support for coroutine debugging and on/off methods to enable debugging for selected code fragments (to improve performance under the debugger) 2012-07-25 23:10:23 -07:00
Paul Kulchenko
2a8e7fe423 Added ignoring Cmd-key combinations on Mac as this should be handled by wxwidgets, but is not (fixes #19) 2012-07-25 16:19:13 -07:00
Paul Kulchenko
cf1a657b80 Updated manifest to add testwell module 2012-07-23 21:13:52 -07:00
crazybutcher
cf6b328a52 lua51 dll forwards to lua5.1.dll 2012-07-22 10:42:05 +02:00
crazybutcher
b0f98f30dc bugfix in interpreter setting 2012-07-21 11:51:56 +02:00
crazybutcher
5c0bf93d9c Merge remote-tracking branch 'zbstudio/master'
Conflicts:
	interpreters/luxinia2.lua
2012-07-21 10:45:23 +02:00
Paul Kulchenko
7b2241085d Added refresh of filetree on MacOS to get it displayed correctly when the app is started 2012-07-14 11:45:57 -07:00
Paul Kulchenko
c9cfd42d34 Corrected resetting of project directory when it's already set and doesn't need to be changed 2012-07-13 23:30:13 -07:00
Paul Kulchenko
c25c56069d Added handling of balanced brackets in markup links 2012-07-13 22:43:27 -07:00
Paul Kulchenko
a68e8f7bd3 Added unit test module 2012-07-13 22:42:35 -07:00
Paul Kulchenko
fc6de036e0 Reorganized handling of font configuration and added font config for filetree (with a different size default on MacOS) 2012-07-13 09:54:52 -07:00
Paul Kulchenko
08d42a2501 Removed setting the editor font in the config as the default font is different on different platforms 2012-07-12 22:07:10 -07:00
Paul Kulchenko
da32878984 Added reporting the number of traced lines during debugging 2012-07-12 14:21:56 -07:00
Paul Kulchenko
3fd5d88656 Reset project directory if the current one doesn't exist 2012-07-11 23:16:33 -07:00
Paul Kulchenko
7d9ad5100c Fixed markup styling and file tree drawing on MacOS 2012-07-11 16:11:11 -07:00
Paul Kulchenko
6bff634446 Added explicit calls to CreateBitmap as wxArtProvider.GetBitmap doesn't alway call a custom art provider on MacOS (2.8.12) and in some cases on msWin (2.8.7) 2012-07-11 13:24:45 -07:00
Paul Kulchenko
b0de487bf0 Fixed detecting executable name in commands with spaces 2012-07-11 13:21:22 -07:00
Paul Kulchenko
560d56835a Fixed typo 2012-07-11 13:20:35 -07:00
Paul Kulchenko
3c6a06f537 Added setting of PATH and CPATH to find proper libs on windows and mac os platforms 2012-07-11 11:24:33 -07:00
Paul Kulchenko
b1f3bf0bd9 Fixed incorrect folders reported in the file tree when no project directory is set and a file is open 2012-07-10 23:32:38 -07:00
Paul Kulchenko
6ea3a4708d Fixed incorrect filename reported in compile errors when the file is not saved 2012-07-10 22:31:06 -07:00
Paul Kulchenko
4de0eb1dc0 Made 'View Stack Window' and 'View Watch Window' refresh window content if it's already shown 2012-07-07 15:08:58 -07:00
Paul Kulchenko
c2f6ed6338 Removed extension from the template to match folders to make it more portable 2012-07-07 11:49:30 -07:00
Paul Kulchenko
fad7ff0cc3 Updated matching of links to make them less greedy (to avoid capturing link terminators) 2012-07-07 11:46:41 -07:00
Paul Kulchenko
9afa35f9b2 Upgraded deprecated constants and logic for compatibility with wxwidgets 2.9.x 2012-07-06 20:54:11 -07:00
Paul Kulchenko
3a5b46f65e Fixed an error thrown when a window with debugging is closed before the application being debugged is terminated 2012-07-06 20:51:01 -07:00
Paul Kulchenko
26d0908c89 Added scratchpad support for love2d 2012-07-03 13:00:18 -07:00
Paul Kulchenko
770db579d9 Added reset of 'modified' status to keep tab names and their config settings correct upon exit 2012-07-03 12:47:18 -07:00
Paul Kulchenko
8e09ed1658 Fixed incorrect storing of settings for editor tabs with the same text (filename). This was causing only one tab displayed for multiple StyledText controls with interesting effects 2012-07-02 11:53:24 -07:00
Paul Kulchenko
25ac96d39a Removed styling of function calls and capturing definitions in strings and comments (fixed #18) 2012-07-01 22:11:03 -07:00
Paul Kulchenko
22fda661ec Updated matching logic for function definitions to allow for a.b.c() definitions (fixes #17) 2012-07-01 21:59:13 -07:00
Paul Kulchenko
529a0e8c9e Added window title update and filetree refresh after SaveAs command 2012-07-01 15:13:12 -07:00
Paul Kulchenko
7cc061e18d Fixed an issue with launching a process when its output is not redirected to the IDE (fixes #16). Added callback for all started processes to make them call OnTerminate event upon completion 2012-07-01 09:44:00 -07:00
Paul Kulchenko
5f2226bac2 Fixed console to evaluate 'function a() ... end' without errors 2012-06-30 11:12:30 -07:00
Paul Kulchenko
37795c2480 Added tooltip to display variable/expression values during debugging 2012-06-30 11:04:48 -07:00
Paul Kulchenko
5e934dfd69 Added checks around ShowFullScreen() calls to avoid failures on those systems that don't provide it (linux/GTK) 2012-06-29 23:39:53 -07:00
Paul Kulchenko
f970ba38a0 Removed setting focus to the Output window when output is processed as it interfered with Run as Scratchpad 2012-06-29 23:35:35 -07:00
Paul Kulchenko
8af6c1b5b6 Fixed a compilation error caused by shebang in scripts 2012-06-29 16:58:25 -07:00
Paul Kulchenko
0777a5fbd8 Added check for debugger calls to avoid errors when debugger is not loaded 2012-06-29 15:31:09 -07:00
Paul Kulchenko
942681e246 Fixed an issue with love2d path with spaces 2012-06-28 20:05:35 -07:00
crazybutcher
46da5b6697 Merge remote-tracking branch 'zbstudio/master'
Conflicts:
	src/editor/debugger.lua
2012-06-25 22:34:07 +02:00
crazybutcher
80f83d781e fix regression, make luxinia2 debuggable again (still issues left with breaking and adding breakpoints when none were active) 2012-06-23 12:02:42 +02:00
74 changed files with 15868 additions and 13257 deletions

235
CHANGELOG.md Normal file
View File

@@ -0,0 +1,235 @@
# ZeroBrane Studio Changelog
## v0.32 (Sep 03 2012)
### Highlights
- Added **Unicode support** for file encoding and file paths on Windows (fixes #30).
- Added **Moai integration and debugging** (including debugging of Moai threads and callbacks).
- Added refresh of Stack and Watch windows after executing a statement in remote shell.
- Added **display of complex values** on multiple lines in shell with '='.
- Added calltip on mouseover for functions during editing and for variables/expressions during debugging.
- Added configuration options to set paths to lua and love2d executables.
- Added support for **coroutine debugging** with stepping through coroutine.resume/.yield calls.
- Updated wx.dll to wxlua 2.8.12.2 and wxwidgets 2.8.12.
- Signed zbstudio app and executable to avoid issues with files not being saved without admin privileges and to remove warning about 'unknown publisher' on windows (fixes #25).
### Improvements
- Added calltip on mouseover for functions during editing and for variables/expressions during debugging.
- Added an IO filter to fix an issue with 0d0d0a line endings on Windows.
- Added support for debugging moai callbacks (upgraded to mobdebug v0.489).
- Added refresh of Stack and Watch windows to show updated values after executing a statement in remote shell.
- Added display of complex values on multiple lines in shell with '='.
- Added rockspec to the list of extensions for lua (fixes #37).
- Added a check to avoid evaluating keywords in tooltip.
- Added current interpreter to the status bar; adding closing debugger when the interpreter is changed.
- Added aborting scratchpad processing when an interpreter can't start or report a fatal error.
- Added support for unicode path files on Windows (fixes #30).
- Added an option to set path to lua executable.
- Added error handler to trap and display debugger errors.
- Added search in PATH for love2d executable.
- Added a workaround for GetExecutablePath() reporting 'wx.dll' instead of a proper exe name with wxlua 2.8.12.2 on Windows.
- Added reporting of function name of the form a.b and a:b in static analysis (fixes #27).
- Added ability for user to keep their settings file in their home directory.
- Added per user settings file. Users can now move their settings file to ~/.zbs/user.lua.
- Added ignoring Cmd-key combinations on Mac as this should be handled by wxwidgets, but is not (fixes #19).
- Added support for coroutine debugging with stepping through coroutine.resume/.yield calls.
- Changed reporting of program execution time from CPU time to user time.
- Changed the call to unhide windows to the async version (ShowWindowAsync) to avoid blocking the IDE when the application doesn't respond.
- Upgraded to wxlua 2.8.12.2 (wxwidgets 2.8.12; unicode version); added lua51.dll proxy (fixes #10 and #7).
- Updated love2d interpreter to use the project folder to check for main.lua.
- Updated test module to use stringified values for comparison.
- Updated status bar style to make it consistent across platforms.
- Removed .bak files from being replaced in when backup copies are saved.
- Removed explicit path conversions and comparisons.
- Refactored LUA_PATH/CPATH processing to set it for all interpreters.
- Signed zbstudio app and executable to avoid issues with files not being saved without admin privileges and to remove warning about 'unknown publisher' on windows (fixes #25).
### Incompatibilities
- Reassigned hotkeys in the Project menu to minimize conflicts on Mac (reassigned Shift-F12 and F11).
### Fixes
- Fixed an issue with double click on analylsis results being out-of-sync when the editor switched to another file (fixes #38)
- Fixed an issue with debugger not activating files with relative path information.
- Fixed 'break' command to work after coming from debugger calls (like on()).
- Fixed an issue with highlighting selected item in the project tree.
- Fixed evaluation of foo:bar in tooltip (now evaluates as foo.bar).
- Fixed debugger termination after internal errors.
- Fixed activating current file in the project tree on Mac (closes #29).
- Fixed running scripts with single quotes in path names.
- Fixed an issue with Run/Debug commands when IDE path includes exclamation mark ('!').
- Fixed an issue with the app not starting on those systems that don't have HOME environment variable; fixes #28.
- Fixed an issue with showing/hiding GUI windows that was occasionally causing a runtime error when the window disappears before it is manipulated.
- Fixed returning proper name for unsaved files in reporting compilation and static analysis results; moved default names to ide.config (fixes #26).
- Fixed pasting text into the Find dialog and project path box on Mac (fixes #22).
- Fixed handling of dashes in paths (upgraded to mobdebug 0.479).
- Reorganized handling of automcomplete event (to use AddPendingEvent instead of PostEvent) to avoid runtime application error.
## v0.31 (Jul 14 2012)
### Highlights
- Added **scratchpad support for love2d**.
- Added tooltip to display variable/expression values during debugging.
- Added **MacOS support**.
### Improvements
- Added handling of balanced brackets in markup links.
- Added unit test module.
- Added reporting the number of traced lines during debugging.
- Added setting of PATH and CPATH to find proper libs on windows and mac os platforms.
- Added scratchpad support for love2d.
- Added reset of 'modified' status to keep tab names and their config settings correct upon exit.
- Added window title update and filetree refresh after SaveAs command.
- Added tooltip to display variable/expression values during debugging.
- Made 'View Stack Window' and 'View Watch Window' refresh window content if it's already shown.
- Removed setting the editor font in the config as the default font is different on different platforms.
- Removed extension from the template to match folders to make it more portable.
- Reorganized handling of font configuration and added font config for filetree (with a different size default on MacOS).
- Updated matching logic for function definitions to allow for a.b.c() definitions (fixes #17).
### Fixes
- Fixed markup styling and file tree drawing on MacOS.
- Fixed detecting executable name in commands with spaces.
- Fixed incorrect folders reported in the file tree when no project directory is set and a file is open.
- Fixed incorrect filename reported in compile errors when the file is not saved.
- Fixed refresh of filetree on MacOS to get it displayed correctly when the app is started.
- Fixed an error thrown when a window with debugging is closed before the application being debugged is terminated.
- Fixed incorrect storing of settings for editor tabs with the same text (filename). This was causing only one tab displayed for multiple StyledText controls with interesting effects.
- Fixed an issue with launching a process when its output is not redirected to the IDE (fixes #16).
- Fixed console to evaluate 'function a() ... end' without errors.
- Fixed a compilation error caused by shebang in scripts.
- Fixed an issue with love2d path with spaces.
- Corrected resetting of project directory when it's already set and doesn't need to be changed.
- Added checks around ShowFullScreen() calls to avoid failures on those systems that don't provide it (linux/GTK).
- Added check for debugger calls to avoid errors when debugger is not loaded.
- Updated matching of links to make them less greedy (to avoid capturing link terminators).
- Upgraded deprecated constants and logic for compatibility with wxwidgets 2.9.x.
- Reset project directory if the current one doesn't exist.
- Removed styling of function calls and capturing definitions in strings and comments (fixed #18).
- Removed setting focus to the Output window when output is processed as it interfered with Run as Scratchpad.
## v0.30 (Jun 27 2012)
### Highlights
- Added **love2d support**.
- Added auto complete for love2d API.
- Added support for debugging processes running under LuaJIT.
- Added display of **hierarchical data in Stack window**.
- Added **pretty printing in Watch and Console** (local and remote) windows and handling of multiple results in Console.
- Added **Stack window to display stack information** and local/upvalue values for each stack frame.
- Added ability to **interact with scripts** by allowing text to be entered in the 'Output' window.
### Improvements
- Added love2d support.
- Added auto complete for love2d API.
- Added support for debugging processes running under LuaJIT.
- Added display of hierarchical data in Stack window.
- Added execution time and updated messages in the Output window to be more consistent.
- Added displaying 'nil' values in local console when no result is returned by an expression.
- Added a check to refuse starting a new debugging session if there is one in progress already.
- Added handling of tail calls in the Stack window.
- Added pretty printing in Watch and Console (local and remote) windows and handling of multiple results in Console.
- Added Stack window to display stack information and local/upvalue values for each stack frame.
- Added ability to set font encoding in the config.
- Added restoring cursor position when a modified file is reloaded in the editor.
- Added ability to interact with scripts by allowing text to be entered in the 'Output' window.
- Improved logic in love2d integration to distinguish Debug and Run commands (closes #13).
- Improved reporting in static analysis for functions and global variables.
- Updated menus to avoid conflicts with MacOS shortcuts.
- Updated logic creating menubar to make it work correctly on MacOS with special Help/About items.
- Updated path handling to better detect how the app is started and to avoid loading dlls on non-windows platforms.
- Updated logic for detecting hostname (used in the debugger) to make sure it is resolvable.
- Changed order of lualibs/ and bin/ directories in package.path and package.cpath to load included modules first.
- Removed extensions from launch commands and updated display logic in the Output window.
### Fixes
- Fixed aborting running/debugged programs on MacOS by adding MAKE_GROUP_LEADER option to wxExecute.
- Fixed an issue in the logic for setting breakpoints, which ignored breakpoints in luxinia2 debug sessions.
- Fixed logic in the local/remote console that returned incorrect error message on executing code like '%s':format(1).
- Fixed IDs for Project menu items to allow them to be removed from the menu if needed.
- Fixed an issue with remote application not terminating when IDE is closed while debugging is in progress.
- Fixed refreshing a modified file when the editor is set to read-only mode.
- Fixed saving/restoring configuration of 'Output'/'Console' tabs when IDE is closed while debugging is in progress.
- Fixed removing variable name in Watch window after escaping editing.
- Fixed #9 as it had incorrect logic in one of UTF filters.
- Fixed edit menu shortcuts to work in the 'Output' window (when allowed).
- Fixed reporting of processes that failed to start after 'Run' or 'Debug' commands.
- Fixed executable path matching to work on systems that don't have file extensions.
- Fixed #3 'unused parameter...' check not to fail on anonymous functions that are part of an expression.
- Moved processing of `user.lua` to a later phase after tools and specs are already loaded to allow modification of IDE configuration from `user.lua`. Closes #5.
- Added checks to prevent text modification in 'Output' and 'Console' windows. Fixes #8.
- Disabled 'Run as Scratchpad' if there is no debugger registered capable of running it.
- Disabled Stack and Watch updates when scratchpad is active as they interfere with application execution.
## v0.29 (May 31 2012)
### Highlights
- Added **scratchpad** (running live) functionality.
- Added **code analyzer** based on lua-inspect.
- Updated **comment styling** to follow markdown syntax.
### Improvements
- Added scratchpad (running live) functionality.
- Added code analyzer based on lua-inspect.
- Added Ctrl(-Shift)-TAB navigation between tabs in the editor.
- Added navigation between editor tabs using Ctrl-PgUp and Ctrl-PgDn.
- Added reporting of assignment to global variables in the code analyzer.
- Added ability to turn external processes that connect to debugger into a scratchpad.
- Added exit from full screen mode using ESC key.
- Added reporting of compilation errors during debugging sessions.
- Added handling of more errors in the shell to allow calculations like '(1+2)' to be executed correctly.
- Added moving focus back to the notebook after unhiding/activating a wx window.
- Added missing mime/code.dll and reorganized socket module files (socket.*) to load correctly with require.
- Added stopping the debugger when a debugged program exits.
- Added to static analysis reporting of unused parameters in functions.
- Disabled warning in static analysis about unused 'self' in methods.
- Removed 'error during pre-compilation' message from compile errors.
- Updated comment styling to follow markdown syntax.
### Fixes
- Fixed handling of scripts with comments in the remote shell.
- Fixed an issue with Analyze process when the analyzed script has compilation errors.
- Fixed an issue with scratchpad being on after Save dialog is canceled.
- Fixed about screen.
## v0.28 (Mar 21 2012)
### Highlights
- Added full screen mode.
### Improvements
- Added option to activate output/console when Run/Debug/Compile commands are executed.
- Added full screen mode.
- Added killing a running process on IDE exit.
- Added killing a running process with Shift-F12.
- Disabled buffering of the output for scripts run from IDE.
### Fixes
- Fixed 'Trace' command to continue working when a debugged file is not activated.
- Fixed an issue with saving a file when no project directory is set.
- Fixed missing semicolon in lualibs path; added path for debugger to search under lualibs.
- Fixed an issue with a missing path separator, which prevented debugging from executing step commands in some cases.
- Fixed missing slash on SaveAs by enforcing trailing slash for the project path.
## v0.27 (Feb 14 2012)
### Highlights
- Added markup formatting in the comments.
### Improvements
- Added markup formatting in the comments.
- Added Debug and Run methods to simulate menu commands.
- Added setting a project folder on initial start.
- Added style processing for font name, font size, visibility and hotspot attributes.
- Added setting the current project directory for the shell to allow 'require' commands to work with local modules.
- Updated markup processing with run and debug commands, http link processing, and opening local files in a new window.
- Enforced visibility for shell prompt.
### Fixes
- Fixed activation of a correct tab when one of the editor tabs is closed.
- Fixed an issue with file activation from a debugger.
- Fixed the issue of ClosePage method being called with two different parameters.
- Fixed the issue of the project dir being returned with two trailing slashes.
- Fixed an issue with activating the currenly edited file in the file tree.
- Wrapped DragAcceptFiles into a protected call to make it not fail on MacOS (compiled with wxwidgets 2.8.12).
## v0.26 (Jan 18 2012)

View File

@@ -71,13 +71,14 @@ ldexp = fn "build floating point number from x and the corresponding integral ex
packUnorm2x16 = fn "Converts each comp. of v into 16-bit ints, packs results into the returned 32-bit uint. - (uint)(vec2 v)",
packUnorm4x8 = fn "Converts each comp. of v into 8-bit ints, packs results into the returned 32-bit uint. - (uint)(vec4 v)",
packSnorm4x8 = fn "Converts each comp. of v into 8-bit ints, packs results into the returned 32-bit uint. - (uint)(vec4 v)",
packDouble2x32 = fn "Packs components of v into a 64-bit value and returns a double-prec value. - (double)(uvec2 v)",
packHalf2x16 = fn "Converts each comp. of v into 16-bit half float, packs results into the returned 32-bit uint. - (uint)(vec2 v)",
unpackUnorm2x16 = fn "Unpacks 32-bit p into two 16-bit uints and converts them to normalized float. - (vec2)(uint p)",
unpackUnorm4x8 = fn "Unpacks 32-bit p into four 8-bit uints and converts them to normalized float. - (vec4)(uint p)",
unpackSnorm4x8 = fn "Unpacks 32-bit p into four 8-bit uints and converts them to normalized float. - (vec4)(uint p)",
packDouble2x32 = fn "Packs components of v into a 64-bit value and returns a double-prec value. - (double)(uvec2 v)",
unpackDouble2x32 = fn "Returns a 2 component vector representation of v. - (uvec2)(double v)",
unpackHalf2x16 = fn "Interprets p as two 16-bit half floats and returns them as vector. - (vec2)(uint p)",
length = fn "return scalar Euclidean length of a vector. - (type)(vecN)",
distance = fn "return the Euclidean distance between two points. - (vecN)(vecN a, b)",
@@ -135,6 +136,11 @@ EndPrimitive = fn "Completes current output primitive and starts a new one. - ()
barrier = fn "Synchronizes across shader invocations. - ()()",
memoryBarrier = fn "control ordering of memory transactions issued by shader thread. - ()()",
memoryBarrierAtomicCounter = fn "control ordering of memory transactions issued by shader thread. - ()()",
memoryBarrierShared = fn "control ordering of memory transactions issued by shader thread. - ()()",
memoryBarrierBuffer = fn "control ordering of memory transactions issued by shader thread. - ()()",
memoryBarrierImage = fn "control ordering of memory transactions issued by shader thread. - ()()",
groupMemoryBarrier = fn "control ordering of memory transactions issued by shader thread. - ()()",
imageAtomicAdd = fn "performs atomic operation on individual texels returns new value. - (uint)(imageN, intN coord, [int sample], uint data)",
imageAtomicMin = fn "performs atomic operation on individual texels returns new value. - (uint)(imageN, intN coord, [int sample], uint data)",
imageAtomicMax = fn "performs atomic operation on individual texels returns new value. - (uint)(imageN, intN coord, [int sample], uint data)",
@@ -167,41 +173,51 @@ texelFetchOffset = fn "integer coordinate lookup for a single texel with offset.
}
local keyw =
[[int uint half float bool double
vec2 vec3 vec4 dvec2 dvec3 dvec4
ivec2 ivec3 ivec4 uvec2 uvec3 uvec4 bvec2 bvec3 bvec4
mat2 mat3 mat4 mat2x2 mat3x3 mat4x4 mat2x3 mat3x2 mat4x2 mat2x4 mat4x3 mat3x4
dmat2 dmat3 dmat4 dmat2x2 dmat3x3 dmat4x4 dmat2x3 dmat3x2 dmat4x2 dmat2x4 dmat4x3 dmat3x4
struct typedef void
usampler1D usampler2D usampler3D usampler2DRect usamplerCube isampler1DArray usampler2DARRAY usamplerCubeArray usampler2DMS usampler2DMSArray
isampler1D isampler2D isampler3D isampler2DRect isamplerCube isampler1DArray isampler2DARRAY isamplerCubeArray isampler2DMS isampler2DMSArray
sampler1D sampler2D sampler3D sampler2DRect samplerCube sampler1DArray sampler2DArray samplerCubeArray sampler2DMS sampler2DMSArray
sampler1DShadow sampler2DShadow sampler2DRectShadow sampler1DArrayShadow sampler2DArrayShadow samplerCubeArrayShadow
usamplerBuffer isamplerBuffer samplerBuffer
in out inout uniform const centroid sample attribute varying patch
return switch case for do while if else break continue
layout location vertices line_strip triangle_strip max_vertices stream
triangles quads equal_spacing isolines fractional_even_spacing
fractional_odd_spacing cw ccw point_mode lines_adjacency triangles_adjacency
invocations
origin_upper_left pixel_center_integer
smooth flat noperspective highp mediump lowp shared packed std140 row_major column_major
gl_FrontColor gl_BackColor gl_FrontSecondaryColor gl_BackSecondaryColor gl_Color gl_SecondaryColor
subroutine gl_Position
gl_VertexID gl_InstanceID gl_Normal gl_Vertex gl_MultiTexCoord0 gl_MultiTexCoord1
gl_MultiTexCoord2 gl_MultiTexCoord3 gl_MultiTexCoord4 gl_MultiTexCoord5 gl_MultiTexCoord6
gl_MultiTexCoord7 gl_FogCoord gl_PointSize gl_ClipDistance
gl_TexCoord gl_FogFragCoord gl_ClipVertex gl_in
gl_PatchVerticesIn
gl_PrimitiveID gl_InvocationID gl_TessLevelOuter gl_TessLevelInner gl_TessCoord
gl_InvocationID gl_PrimitiveIDIn gl_Layer gl_ViewportIndex gl_FrontFacing
gl_PointCoord gl_SampleID gl_SamplePosition gl_FragColor
gl_FragData gl_FragDepth gl_SampleMask
[[ int uint half float bool double atomic_uint binding offset
vec2 vec3 vec4 dvec2 dvec3 dvec4
ivec2 ivec3 ivec4 uvec2 uvec3 uvec4 bvec2 bvec3 bvec4
mat2 mat3 mat4 mat2x2 mat3x3 mat4x4 mat2x3 mat3x2 mat4x2 mat2x4 mat4x3 mat3x4
dmat2 dmat3 dmat4 dmat2x2 dmat3x3 dmat4x4 dmat2x3 dmat3x2 dmat4x2 dmat2x4 dmat4x3 dmat3x4
struct typedef void
usampler1D usampler2D usampler3D usampler2DRect usamplerCube isampler1DArray usampler2DARRAY usamplerCubeArray usampler2DMS usampler2DMSArray
isampler1D isampler2D isampler3D isampler2DRect isamplerCube isampler1DArray isampler2DARRAY isamplerCubeArray isampler2DMS isampler2DMSArray
sampler1D sampler2D sampler3D sampler2DRect samplerCube sampler1DArray sampler2DArray samplerCubeArray sampler2DMS sampler2DMSArray
sampler1DShadow sampler2DShadow sampler2DRectShadow sampler1DArrayShadow sampler2DArrayShadow samplerCubeArrayShadow
usamplerBuffer isamplerBuffer samplerBuffer samplerRenderbuffer isamplerRenderbuffer usamplerRenderbuffer
in out inout uniform const centroid sample attribute varying patch index true false
return switch case for do while if else break continue main inline
layout location vertices line_strip triangle_strip max_vertices stream
triangles quads equal_spacing isolines fractional_even_spacing lines points
fractional_odd_spacing cw ccw point_mode lines_adjacency triangles_adjacency
invocations
origin_upper_left pixel_center_integer depth_greater depth_greater depth_greater depth_unchanged
smooth flat noperspective highp mediump lowp shared packed std140 std430 row_major column_major buffer
gl_FrontColor gl_BackColor gl_FrontSecondaryColor gl_BackSecondaryColor gl_Color gl_SecondaryColor
subroutine gl_Position gl_FragCoord
gl_VertexID gl_InstanceID gl_Normal gl_Vertex gl_MultiTexCoord0 gl_MultiTexCoord1
gl_MultiTexCoord2 gl_MultiTexCoord3 gl_MultiTexCoord4 gl_MultiTexCoord5 gl_MultiTexCoord6
gl_MultiTexCoord7 gl_FogCoord gl_PointSize gl_ClipDistance
gl_TexCoord gl_FogFragCoord gl_ClipVertex gl_in
gl_PatchVerticesIn
gl_PrimitiveID gl_InvocationID gl_TessLevelOuter gl_TessLevelInner gl_TessCoord
gl_InvocationID gl_PrimitiveIDIn gl_Layer gl_ViewportIndex gl_FrontFacing
gl_PointCoord gl_SampleID gl_SamplePosition gl_FragColor
gl_FragData gl_FragDepth gl_SampleMask
gl_NumWorkGroups gl_WorkGroupSize gl_WorkGroupID gl_LocalInvocationID gl_GlobalInvocationID gl_LocalInvocationIndex
local_size_x local_size_y local_size_z
coherent volatile restrict readonly writeonly
image1D image2D image3D image2DRect imageCube imageBuffer image1DArray image2DArray imageCubeArray image2DMS image2DMSArray
uimage1D uimage2D uimage3D uimage2DRect uimageCube uimageBuffer uimage1DArray uimage2DArray uimageCubeArray uimage2DMS uimage2DMSArray
iimage1D iimage2D iimage3D iimage2DRect iimageCube iimageBuffer iimage1DArray iimage2DArray iimageCubeArray iimage2DMS iimage2DMSArray
size1x8 size1x16 size1x32 size2x32 size4x32 rgba32f rgba16f rg32f rg16f r32f r16f rgba8 rgba16 r11f_g11f_b10f rgb10_a2ui
rgb10_a2i rg16 rg8 r16 r8 rgba32i rgba16i rgba8i rg32i rg16i rg8i r32i r16i r8i rgba32ui rgba16ui rgba8ui rg32ui rg16ui rg8ui
r32ui r16ui r8ui rgba16_snorm rgba8_snorm rg16_snorm rg8_snorm r16_snorm r8_snorm
]]
-- keywords - shouldn't be left out
for w in keyw:gmatch("([a-zA-Z_0-9]+)") do
api[w] = {type="keyword"}
api[w] = {type="keyword"}
end
return api

553
api/lua/anttweakbar.lua Normal file
View File

@@ -0,0 +1,553 @@
--[[// tw tweakbar | AntTweakBar UI
enum { TW_VERSION = 114 }
typedef enum ETwType {
TW_TYPE_UNDEF,
TW_TYPE_BOOLCPP,
TW_TYPE_BOOL8,
TW_TYPE_BOOL16,
TW_TYPE_BOOL32,
TW_TYPE_CHAR,
TW_TYPE_INT8,
TW_TYPE_UINT8,
TW_TYPE_INT16,
TW_TYPE_UINT16,
TW_TYPE_INT32,
TW_TYPE_UINT32,
TW_TYPE_FLOAT,
TW_TYPE_DOUBLE,
TW_TYPE_COLOR32, // 32 bits color. Order is RGBA if API is OpenGL or Direct3D10, and inversed if API is Direct3D9 (can be modified by defining 'colorOrder=...', see doc)
TW_TYPE_COLOR3F, // 3 floats color. Order is RGB.
TW_TYPE_COLOR4F, // 4 floats color. Order is RGBA.
TW_TYPE_CDSTRING, // Null-terminated C Dynamic String (pointer to an array of char dynamically allocated with malloc/realloc/strdup)
TW_TYPE__TEMP1, //
TW_TYPE_QUAT4F, // 4 floats encoding a quaternion {qx,qy,qz,qs}
TW_TYPE_QUAT4D, // 4 doubles encoding a quaternion {qx,qy,qz,qs}
TW_TYPE_DIR3F, // direction vector represented by 3 floats
TW_TYPE_DIR3D, // direction vector represented by 3 doubles
TW_TYPE_CSSTRING_LEN0 = 0x30000000,
TW_TYPE_CSSTRING_LEN256 = 0x30000000 + 256,
} TwType;
typedef struct CTwEnumVal {
int Value;
const char * Label;
} TwEnumVal;
typedef struct CTwStructMember {
const char * Name;
TwType Type;
size_t Offset;
const char * DefString;
} TwStructMember;
typedef enum ETwParamValueType {
TW_PARAM_INT32,
TW_PARAM_FLOAT,
TW_PARAM_DOUBLE,
TW_PARAM_CSTRING // Null-terminated array of char (ie, c-string)
} TwParamValueType;
typedef enum ETwGraphAPI {
TW_OPENGL = 1,
TW_DIRECT3D9 = 2,
TW_DIRECT3D10 = 3,
TW_DIRECT3D11 = 4
} TwGraphAPI;
typedef enum ETwKeyModifier {
TW_KMOD_NONE = 0x0000, // same codes as SDL keysym.mod
TW_KMOD_SHIFT = 0x0003,
TW_KMOD_CTRL = 0x00c0,
TW_KMOD_ALT = 0x0100,
TW_KMOD_META = 0x0c00
} TwKeyModifier;
typedef enum EKeySpecial {
TW_KEY_BACKSPACE = '\b',
TW_KEY_TAB = '\t',
TW_KEY_CLEAR = 0x0c,
TW_KEY_RETURN = '\r',
TW_KEY_PAUSE = 0x13,
TW_KEY_ESCAPE = 0x1b,
TW_KEY_SPACE = ' ',
TW_KEY_DELETE = 0x7f,
TW_KEY_UP = 273,
TW_KEY_DOWN,
TW_KEY_RIGHT,
TW_KEY_LEFT,
TW_KEY_INSERT,
TW_KEY_HOME,
TW_KEY_END,
TW_KEY_PAGE_UP,
TW_KEY_PAGE_DOWN,
TW_KEY_F1,
TW_KEY_F2,
TW_KEY_F3,
TW_KEY_F4,
TW_KEY_F5,
TW_KEY_F6,
TW_KEY_F7,
TW_KEY_F8,
TW_KEY_F9,
TW_KEY_F10,
TW_KEY_F11,
TW_KEY_F12,
TW_KEY_F13,
TW_KEY_F14,
TW_KEY_F15,
TW_KEY_LAST
} TwKeySpecial;
typedef enum ETwMouseAction {
TW_MOUSE_RELEASED,
TW_MOUSE_PRESSED
} TwMouseAction;
typedef enum ETwMouseButtonID {
TW_MOUSE_LEFT = 1,
TW_MOUSE_MIDDLE = 2,
TW_MOUSE_RIGHT = 3
} TwMouseButtonID;
typedef void (*TwSetVarCallback) ( const void *value, void *clientData );
typedef void (*TwGetVarCallback) ( void *value, void *clientData );
typedef void (*TwButtonCallback) ( void *clientData );
typedef void (*TwSummaryCallback) ( char *summaryString, size_t summaryMaxLength, const void *value, void *clientData );
typedef void (*TwCopyCDStringToClient) ( char **destinationClientStringPtr, const char *sourceString );
typedef void (*TwErrorHandler) ( const char *errorMessage );
typedef void (*TwGLUTmousebuttonfun) ( int glutButton, int glutState, int mouseX, int mouseY );
typedef void (*TwGLUTmousemotionfun) ( int mouseX, int mouseY );
typedef void (*TwGLUTkeyboardfun) ( unsigned char glutKey, int mouseX, int mouseY );
typedef void (*TwGLUTspecialfun) ( int glutKey, int mouseX, int mouseY );
typedef struct CTwBar TwBar;
TwBar* TwNewBar( const char *barName );
int TwDeleteBar( TwBar *bar );
int TwDeleteAllBars( );
int TwSetTopBar( const TwBar *bar );
TwBar* TwGetTopBar( );
int TwSetBottomBar( const TwBar *bar );
TwBar* TwGetBottomBar( );
const char* TwGetBarName( TwBar *bar );
int TwGetBarCount( );
TwBar* TwGetBarByIndex( int barIndex );
TwBar* TwGetBarByName( const char *barName );
int TwRefreshBar( TwBar *bar );
int TwAddVarRW( TwBar *bar, const char *name, TwType type, void *var, const char *def );
int TwAddVarRO( TwBar *bar, const char *name, TwType type, const void *var, const char *def );
int TwAddVarCB( TwBar *bar, const char *name, TwType type, TwSetVarCallback setCallback, TwGetVarCallback getCallback, void *clientData, const char *def );
int TwAddButton( TwBar *bar, const char *name, TwButtonCallback callback, void *clientData, const char *def );
int TwAddSeparator( TwBar *bar, const char *name, const char *def );
int TwRemoveVar( TwBar *bar, const char *name );
int TwRemoveAllVars( TwBar *bar );
int TwDefine( const char *def );
TwType TwDefineEnum( const char *name, const TwEnumVal *enumValues, unsigned int nbValues );
TwType TwDefineEnumFromString( const char *name, const char *enumString );
TwType TwDefineStruct( const char *name, const TwStructMember *structMembers, unsigned int nbMembers, size_t structSize, TwSummaryCallback summaryCallback, void *summaryClientData );
void TwCopyCDStringToClientFunc( TwCopyCDStringToClient copyCDStringFunc );
void TwCopyCDStringToLibrary( char **destinationLibraryStringPtr, const char *sourceClientString );
int TwGetParam( TwBar *bar, const char *varName, const char *paramName, TwParamValueType paramValueType, unsigned int outValueMaxCount, void *outValues );
int TwSetParam( TwBar *bar, const char *varName, const char *paramName, TwParamValueType paramValueType, unsigned int inValueCount, const void *inValues );
int TwInit( TwGraphAPI graphAPI, void *device );
int TwTerminate();
int TwDraw();
int TwWindowSize( int width, int height);
int TwSetCurrentWindow( int windowID); // multi-windows support
int TwGetCurrentWindow();
int TwWindowExists( int windowID);
int TwKeyPressed( int key, int modifiers);
int TwKeyTest( int key, int modifiers);
int TwMouseButton( TwMouseAction action, TwMouseButtonID button);
int TwMouseMotion( int mouseX, int mouseY);
int TwMouseWheel( int pos);
const char* TwGetLastError( );
void TwHandleErrors( TwErrorHandler errorHandler);
int TwEventSDL( const void *sdlEvent, unsigned char sdlMajorVersion, unsigned char sdlMinorVersion);
int TwEventSDL12( const void *sdlEvent);
int TwEventSDL13( const void *sdlEvent);
int TwEventMouseButtonGLFW( int glfwButton, int glfwAction );
int TwEventKeyGLFW( int glfwKey, int glfwAction );
int TwEventCharGLFW( int glfwChar, int glfwAction );
int TwEventMouseButtonGLUT( int glutButton, int glutState, int mouseX, int mouseY);
int TwEventMouseMotionGLUT( int mouseX, int mouseY);
int TwEventKeyboardGLUT( unsigned char glutKey, int mouseX, int mouseY );
int TwEventSpecialGLUT( int glutKey, int mouseX, int mouseY );
int TwGLUTModifiersFunc( int (*glutGetModifiersFunc)(void) );
int TwEventSFML( const void *sfmlEvent, unsigned char sfmlMajorVersion, unsigned char sfmlMinorVersion);
]]
--auto-generated api from ffi headers
local api =
{
["TW_TYPE_UNDEF"] = { type ='value', },
["TW_TYPE_BOOLCPP"] = { type ='value', },
["TW_TYPE_BOOL8"] = { type ='value', },
["TW_TYPE_BOOL16"] = { type ='value', },
["TW_TYPE_BOOL32"] = { type ='value', },
["TW_TYPE_CHAR"] = { type ='value', },
["TW_TYPE_INT8"] = { type ='value', },
["TW_TYPE_UINT8"] = { type ='value', },
["TW_TYPE_INT16"] = { type ='value', },
["TW_TYPE_UINT16"] = { type ='value', },
["TW_TYPE_INT32"] = { type ='value', },
["TW_TYPE_UINT32"] = { type ='value', },
["TW_TYPE_FLOAT"] = { type ='value', },
["TW_TYPE_DOUBLE"] = { type ='value', },
["TW_TYPE_COLOR32"] = { type ='value', },
["TW_TYPE_COLOR3F"] = { type ='value', },
["TW_TYPE_COLOR4F"] = { type ='value', },
["TW_TYPE_CDSTRING"] = { type ='value', },
["TW_TYPE__TEMP1"] = { type ='value', },
["TW_TYPE_QUAT4F"] = { type ='value', },
["TW_TYPE_QUAT4D"] = { type ='value', },
["TW_TYPE_DIR3F"] = { type ='value', },
["TW_TYPE_DIR3D"] = { type ='value', },
["TW_TYPE_CSSTRING_LEN0"] = { type ='value', },
["TW_TYPE_CSSTRING_LEN256"] = { type ='value', },
["TW_PARAM_INT32"] = { type ='value', },
["TW_PARAM_FLOAT"] = { type ='value', },
["TW_PARAM_DOUBLE"] = { type ='value', },
["TW_PARAM_CSTRING"] = { type ='value', },
["TW_OPENGL"] = { type ='value', },
["TW_DIRECT3D9"] = { type ='value', },
["TW_DIRECT3D10"] = { type ='value', },
["TW_DIRECT3D11"] = { type ='value', },
["TW_KMOD_NONE"] = { type ='value', },
["TW_KMOD_SHIFT"] = { type ='value', },
["TW_KMOD_CTRL"] = { type ='value', },
["TW_KMOD_ALT"] = { type ='value', },
["TW_KMOD_META"] = { type ='value', },
["TW_KEY_BACKSPACE"] = { type ='value', },
["TW_KEY_TAB"] = { type ='value', },
["TW_KEY_CLEAR"] = { type ='value', },
["TW_KEY_RETURN"] = { type ='value', },
["TW_KEY_PAUSE"] = { type ='value', },
["TW_KEY_ESCAPE"] = { type ='value', },
["TW_KEY_SPACE"] = { type ='value', },
["TW_KEY_DELETE"] = { type ='value', },
["TW_KEY_UP"] = { type ='value', },
["TW_KEY_DOWN"] = { type ='value', },
["TW_KEY_RIGHT"] = { type ='value', },
["TW_KEY_LEFT"] = { type ='value', },
["TW_KEY_INSERT"] = { type ='value', },
["TW_KEY_HOME"] = { type ='value', },
["TW_KEY_END"] = { type ='value', },
["TW_KEY_PAGE_UP"] = { type ='value', },
["TW_KEY_PAGE_DOWN"] = { type ='value', },
["TW_KEY_F1"] = { type ='value', },
["TW_KEY_F2"] = { type ='value', },
["TW_KEY_F3"] = { type ='value', },
["TW_KEY_F4"] = { type ='value', },
["TW_KEY_F5"] = { type ='value', },
["TW_KEY_F6"] = { type ='value', },
["TW_KEY_F7"] = { type ='value', },
["TW_KEY_F8"] = { type ='value', },
["TW_KEY_F9"] = { type ='value', },
["TW_KEY_F10"] = { type ='value', },
["TW_KEY_F11"] = { type ='value', },
["TW_KEY_F12"] = { type ='value', },
["TW_KEY_F13"] = { type ='value', },
["TW_KEY_F14"] = { type ='value', },
["TW_KEY_F15"] = { type ='value', },
["TW_KEY_LAST"] = { type ='value', },
["TW_MOUSE_RELEASED"] = { type ='value', },
["TW_MOUSE_PRESSED"] = { type ='value', },
["TW_MOUSE_LEFT"] = { type ='value', },
["TW_MOUSE_MIDDLE"] = { type ='value', },
["TW_MOUSE_RIGHT"] = { type ='value', },
["TwNewBar"] = { type ='function',
description = "",
returns = "(TwBar*)",
valuetype = nil,
args = "(const char *barName)", },
["TwDeleteBar"] = { type ='function',
description = "",
returns = "(int)",
valuetype = nil,
args = "(TwBar *bar)", },
["TwDeleteAllBars"] = { type ='function',
description = "",
returns = "(int)",
valuetype = nil,
args = "()", },
["TwSetTopBar"] = { type ='function',
description = "",
returns = "(int)",
valuetype = nil,
args = "(const TwBar *bar)", },
["TwGetTopBar"] = { type ='function',
description = "",
returns = "(TwBar*)",
valuetype = nil,
args = "()", },
["TwSetBottomBar"] = { type ='function',
description = "",
returns = "(int)",
valuetype = nil,
args = "(const TwBar *bar)", },
["TwGetBottomBar"] = { type ='function',
description = "",
returns = "(TwBar*)",
valuetype = nil,
args = "()", },
["TwGetBarName"] = { type ='function',
description = "",
returns = "(const char*)",
valuetype = "string",
args = "(TwBar *bar)", },
["TwGetBarCount"] = { type ='function',
description = "",
returns = "(int)",
valuetype = nil,
args = "()", },
["TwGetBarByIndex"] = { type ='function',
description = "",
returns = "(TwBar*)",
valuetype = nil,
args = "(int barIndex)", },
["TwGetBarByName"] = { type ='function',
description = "",
returns = "(TwBar*)",
valuetype = nil,
args = "(const char *barName)", },
["TwRefreshBar"] = { type ='function',
description = "",
returns = "(int)",
valuetype = nil,
args = "(TwBar *bar)", },
["TwAddVarRW"] = { type ='function',
description = "",
returns = "(int)",
valuetype = nil,
args = "(TwBar *bar, const char *name, TwType type, void *var, const char *def)", },
["TwAddVarRO"] = { type ='function',
description = "",
returns = "(int)",
valuetype = nil,
args = "(TwBar *bar, const char *name, TwType type, const void *var, const char *def)", },
["TwAddVarCB"] = { type ='function',
description = "",
returns = "(int)",
valuetype = nil,
args = "(TwBar *bar, const char *name, TwType type, TwSetVarCallback setCallback, TwGetVarCallback getCallback, void *clientData, const char *def)", },
["TwAddButton"] = { type ='function',
description = "",
returns = "(int)",
valuetype = nil,
args = "(TwBar *bar, const char *name, TwButtonCallback callback, void *clientData, const char *def)", },
["TwAddSeparator"] = { type ='function',
description = "",
returns = "(int)",
valuetype = nil,
args = "(TwBar *bar, const char *name, const char *def)", },
["TwRemoveVar"] = { type ='function',
description = "",
returns = "(int)",
valuetype = nil,
args = "(TwBar *bar, const char *name)", },
["TwRemoveAllVars"] = { type ='function',
description = "",
returns = "(int)",
valuetype = nil,
args = "(TwBar *bar)", },
["TwDefine"] = { type ='function',
description = "",
returns = "(int)",
valuetype = nil,
args = "(const char *def)", },
["TwDefineEnum"] = { type ='function',
description = "",
returns = "(TwType)",
valuetype = nil,
args = "(const char *name, const TwEnumVal *enumValues, unsigned int nbValues)", },
["TwDefineEnumFromString"] = { type ='function',
description = "",
returns = "(TwType)",
valuetype = nil,
args = "(const char *name, const char *enumString)", },
["TwDefineStruct"] = { type ='function',
description = "",
returns = "(TwType)",
valuetype = nil,
args = "(const char *name, const TwStructMember *structMembers, unsigned int nbMembers, size_t structSize, TwSummaryCallback summaryCallback, void *summaryClientData)", },
["TwCopyCDStringToClientFunc"] = { type ='function',
description = "",
returns = "(void)",
valuetype = nil,
args = "(TwCopyCDStringToClient copyCDStringFunc)", },
["TwCopyCDStringToLibrary"] = { type ='function',
description = "",
returns = "(void)",
valuetype = nil,
args = "(char **destinationLibraryStringPtr, const char *sourceClientString)", },
["TwGetParam"] = { type ='function',
description = "",
returns = "(int)",
valuetype = nil,
args = "(TwBar *bar, const char *varName, const char *paramName, TwParamValueType paramValueType, unsigned int outValueMaxCount, void *outValues)", },
["TwSetParam"] = { type ='function',
description = "",
returns = "(int)",
valuetype = nil,
args = "(TwBar *bar, const char *varName, const char *paramName, TwParamValueType paramValueType, unsigned int inValueCount, const void *inValues)", },
["TwInit"] = { type ='function',
description = "",
returns = "(int)",
valuetype = nil,
args = "(TwGraphAPI graphAPI, void *device)", },
["TwTerminate"] = { type ='function',
description = "",
returns = "(int)",
valuetype = nil,
args = "()", },
["TwDraw"] = { type ='function',
description = "",
returns = "(int)",
valuetype = nil,
args = "()", },
["TwWindowSize"] = { type ='function',
description = "",
returns = "(int)",
valuetype = nil,
args = "(int width, int height)", },
["TwSetCurrentWindow"] = { type ='function',
description = "",
returns = "(int)",
valuetype = nil,
args = "(int windowID)", },
["TwGetCurrentWindow"] = { type ='function',
description = "",
returns = "(int)",
valuetype = nil,
args = "()", },
["TwWindowExists"] = { type ='function',
description = "",
returns = "(int)",
valuetype = nil,
args = "(int windowID)", },
["TwKeyPressed"] = { type ='function',
description = "",
returns = "(int)",
valuetype = nil,
args = "(int key, int modifiers)", },
["TwKeyTest"] = { type ='function',
description = "",
returns = "(int)",
valuetype = nil,
args = "(int key, int modifiers)", },
["TwMouseButton"] = { type ='function',
description = "",
returns = "(int)",
valuetype = nil,
args = "(TwMouseAction action, TwMouseButtonID button)", },
["TwMouseMotion"] = { type ='function',
description = "",
returns = "(int)",
valuetype = nil,
args = "(int mouseX, int mouseY)", },
["TwMouseWheel"] = { type ='function',
description = "",
returns = "(int)",
valuetype = nil,
args = "(int pos)", },
["TwGetLastError"] = { type ='function',
description = "",
returns = "(const char*)",
valuetype = "string",
args = "()", },
["TwHandleErrors"] = { type ='function',
description = "",
returns = "(void)",
valuetype = nil,
args = "(TwErrorHandler errorHandler)", },
["TwEventSDL"] = { type ='function',
description = "",
returns = "(int)",
valuetype = nil,
args = "(const void *sdlEvent, unsigned char sdlMajorVersion, unsigned char sdlMinorVersion)", },
["TwEventSDL12"] = { type ='function',
description = "",
returns = "(int)",
valuetype = nil,
args = "(const void *sdlEvent)", },
["TwEventSDL13"] = { type ='function',
description = "",
returns = "(int)",
valuetype = nil,
args = "(const void *sdlEvent)", },
["TwEventMouseButtonGLFW"] = { type ='function',
description = "",
returns = "(int)",
valuetype = nil,
args = "(int glfwButton, int glfwAction)", },
["TwEventKeyGLFW"] = { type ='function',
description = "",
returns = "(int)",
valuetype = nil,
args = "(int glfwKey, int glfwAction)", },
["TwEventCharGLFW"] = { type ='function',
description = "",
returns = "(int)",
valuetype = nil,
args = "(int glfwChar, int glfwAction)", },
["TwEventMouseButtonGLUT"] = { type ='function',
description = "",
returns = "(int)",
valuetype = nil,
args = "(int glutButton, int glutState, int mouseX, int mouseY)", },
["TwEventMouseMotionGLUT"] = { type ='function',
description = "",
returns = "(int)",
valuetype = nil,
args = "(int mouseX, int mouseY)", },
["TwEventKeyboardGLUT"] = { type ='function',
description = "",
returns = "(int)",
valuetype = nil,
args = "(unsigned char glutKey, int mouseX, int mouseY)", },
["TwEventSpecialGLUT"] = { type ='function',
description = "",
returns = "(int)",
valuetype = nil,
args = "(int glutKey, int mouseX, int mouseY)", },
["glutGetModifiersFunc"] = { type ='function',
description = "",
returns = "(int)",
valuetype = nil,
args = "(void))", },
["TwEventSFML"] = { type ='function',
description = "",
returns = "(int)",
valuetype = nil,
args = "(const void *sfmlEvent, unsigned char sfmlMajorVersion, unsigned char sfmlMinorVersion)", },
["TwEnumVal"] = { type ='class',
description = "",
childs = {
["Value"] = { type ='value', description = "int ", valuetype = nil, },
["Label"] = { type ='value', description = "const char * ", valuetype = "string", },
}
},
["TwStructMember"] = { type ='class',
description = "",
childs = {
["Name"] = { type ='value', description = "const char * ", valuetype = "string", },
["Type"] = { type ='value', description = "TwType ", valuetype = nil, },
["Offset"] = { type ='value', description = "size_t ", valuetype = nil, },
["DefString"] = { type ='value', description = "const char * ", valuetype = "string", },
}
},
}
return {
tw = {
type = 'lib',
description = "AntTweakBar UI",
childs = api,
},
tweakbar = {
type = 'lib',
description = "AntTweakBar UI",
childs = api,
},
}

File diff suppressed because it is too large Load Diff

Binary file not shown.

BIN
bin/lua51.dll Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -4,7 +4,8 @@ Configuration files are loaded in the following order
1. <application>\config.lua
2. cfg\user.lua
3. -cfg commandline strings
3. ~\.zbs\user.lua
4. -cfg commandline strings
-- an example of how loaded configuration can be modified from this file
@@ -13,15 +14,22 @@ local luaspec = G.ide.specs['lua']
luaspec.exts[2] = "luaz"
luaspec.keywords[1] = luaspec.keywords[1] .. ' foo'
-- these changes are going to be mapped to ide.config.editor...
-- change encoding to Cyrillic
editor.fontencoding = G.wx.wxFONTENCODING_ISO8859_5
-- or WinCyrillic
editor.fontencoding = G.wx.wxFONTENCODING_CP1251
outputshell.fontencoding = G.wx.wxFONTENCODING_CP1251
-- change font size to 12
editor.fontsize = 12 -- this is mapped to ide.config.editor.fontsize
filehistorylength = 20 -- this is mapped to ide.config.filehistorylength
-- specify full path to love2d executable; this is only needed
-- if the game folder and the executable are NOT in the same folder.
path.love2d = 'd:/lua/love/love' -- set the path of love executable
path.love2d = 'd:/lua/love/love'
-- specify full path to moai executable if it's not in one of PATH folders
path.moai = 'd:/lua/moai/moai'
-- specify full path to lua interpreter if you need to use your own version
path.lua = 'd:/lua/lua'
-- fix an issue with 0d0d0a line endings in MOAI examples,
-- which may negatively affect breakpoints during debugging
editor.iofilter = "0d0d0aFix"
--]]--

View File

@@ -1,14 +1,38 @@
local love2d
local win = ide.osname == "Windows"
return {
name = "Love2d",
description = "Love2d game engine",
api = {"baselib", "love2d"},
frun = function(self,wfilename,rundebug)
love2d = love2d or ide.config.path.love2d -- check if the path is configured
if not love2d then
local sep = win and ';' or ':'
local path = (os.getenv('PATH') or '')..sep
..(GetPathWithSep(self:fworkdir(wfilename)))..sep
..(os.getenv('HOME') and GetPathWithSep(os.getenv('HOME'))..'bin' or '')
local paths = {}
for p in path:gmatch("[^"..sep.."]+") do
love2d = love2d or GetFullPathIfExists(p, win and 'love.exe' or 'love')
table.insert(paths, p)
end
if not love2d then
DisplayOutput("Can't find love2d executable in any of the following folders: "
..table.concat(paths, ", ").."\n")
return
end
end
if not GetFullPathIfExists(self:fworkdir(wfilename), 'main.lua') then
DisplayOutput("Can't find 'main.lua' file in the current project folder.\n")
return
end
if rundebug then DebuggerAttachDefault() end
local love2d = ide.config.path.love2d
or wx.wxFileName(self:fprojdir(wfilename)):GetPath(wx.wxPATH_GET_VOLUME)
.. '/love'
local cmd = string.gsub(love2d, "\\","/") .. ' "' .. self:fprojdir(wfilename) .. '"'
.. (rundebug and ' -debug' or '')
local cmd = ('"%s" "%s"%s'):format(love2d,
self:fworkdir(wfilename), rundebug and ' -debug' or '')
-- CommandLineRun(cmd,wdir,tooutput,nohide,stringcallback,uid,endcallback)
return CommandLineRun(cmd,self:fworkdir(wfilename),true,false,nil,nil,
function() ide.debugger.pid = nil end)
@@ -16,12 +40,10 @@ return {
fprojdir = function(self,wfilename)
return wfilename:GetPath(wx.wxPATH_GET_VOLUME)
end,
fworkdir = function (self,wfilename)
return ide.config.path.projectdir
or wfilename:GetPath(wx.wxPATH_GET_VOLUME)
fworkdir = function(self,wfilename)
return ide.config.path.projectdir or wfilename:GetPath(wx.wxPATH_GET_VOLUME)
end,
hasdebugger = true,
fattachdebug = function(self)
DebuggerAttachDefault()
end,
fattachdebug = function(self) DebuggerAttachDefault() end,
scratchextloop = true,
}

View File

@@ -1,23 +1,39 @@
local exe
local function exePath()
local mainpath = ide.editorFilename:gsub("[^/\\]+$","")
local macExe = mainpath..'bin/lua.app/Contents/MacOS/lua'
return ide.config.path.lua or
(ide.osname == "Windows" and mainpath..[[bin\lua]]
or (wx.wxFileExists(macExe) and macExe or mainpath..'bin/lua'))
end
return {
name = "Lua with Debugger",
name = "Lua",
description = "Lua interpreter with debugger",
api = {"wxwidgets","baselib"},
frun = function(self,wfilename,rundebug)
local mainpath = string.gsub(ide.editorFilename:gsub("[^/\\]+$",""),"\\","/")
local filepath = string.gsub(wfilename:GetFullPath(), "\\","/")
exe = exe or exePath()
local filepath = wfilename:GetFullPath()
local script
if rundebug then
DebuggerAttachDefault()
script = (
"package.path=package.path..';"..mainpath.."lualibs/?/?.lua;"..mainpath.."lualibs/?.lua';"..
"package.cpath=package.cpath..';"..mainpath.."bin/clibs/?.dll';"..
rundebug
)
script = rundebug
else
script = ([[dofile '%s']]):format(filepath)
-- if running on Windows and can't open the file, this may mean that
-- the file path includes unicode characters that need special handling
local fh = io.open(filepath, "r")
if fh then fh:close() end
if ide.osname == 'Windows' and pcall(require, "winapi")
and wfilename:FileExists() and not fh then
winapi.set_encoding(winapi.CP_UTF8)
filepath = winapi.short_path(filepath)
end
script = ('dofile [[%s]]'):format(filepath)
end
local code = ([[xpcall(function() io.stdout:setvbuf('no'); %s end,function(err) print(debug.traceback(err)) end)]]):format(script)
local cmd = '"'..mainpath..'bin/lua" -e "'..code..'"'
local cmd = '"'..exe..'" -e "'..code..'"'
-- CommandLineRun(cmd,wdir,tooutput,nohide,stringcallback,uid,endcallback)
return CommandLineRun(cmd,self:fworkdir(wfilename),true,false,nil,nil,
function() ide.debugger.pid = nil end)
@@ -26,11 +42,8 @@ return {
return wfilename:GetPath(wx.wxPATH_GET_VOLUME)
end,
fworkdir = function (self,wfilename)
return ide.config.path.projectdir
or wfilename:GetPath(wx.wxPATH_GET_VOLUME)
return ide.config.path.projectdir or wfilename:GetPath(wx.wxPATH_GET_VOLUME)
end,
hasdebugger = true,
fattachdebug = function(self)
DebuggerAttachDefault()
end,
fattachdebug = function(self) DebuggerAttachDefault() end,
}

View File

@@ -77,6 +77,7 @@ return {
if not rundebug then
local client = self:finitclient()
ShellSupportRemote(client,self:fuid(wfilename))
pid = nil
end
return pid

85
interpreters/moai.lua Normal file
View File

@@ -0,0 +1,85 @@
local moai
local win = ide.osname == "Windows"
return {
name = "Moai",
description = "Moai mobile platform",
api = {"baselib"},
frun = function(self,wfilename,rundebug)
moai = moai or ide.config.path.moai -- check if the path is configured
if not moai then
local sep = win and ';' or ':'
local path = (os.getenv('PATH') or '')..sep
..(os.getenv('MOAI_BIN') or '')..sep
..(os.getenv('HOME') and os.getenv('HOME') .. '/bin' or '')
local paths = {}
for p in path:gmatch("[^"..sep.."]+") do
moai = moai or GetFullPathIfExists(p, win and 'moai.exe' or 'moai')
table.insert(paths, p)
end
if not moai then
DisplayOutput("Can't find moai executable in any of the folders in PATH or MOAI_BIN: "
..table.concat(paths, ", ").."\n")
return
end
end
local file
local epoints = ide.config.moai and ide.config.moai.entrypoints
if epoints then
epoints = type(epoints) == 'table' and epoints or {epoints}
for _,entry in pairs(epoints) do
file = GetFullPathIfExists(self:fworkdir(wfilename), entry)
if file then break end
end
if not file then
DisplayOutput("Can't find any of the specified entry points ("
..table.concat(epoints, ", ")
..") in the current project; continuing with the current file...\n")
end
end
if rundebug then
-- start running the application right away
DebuggerAttachDefault({runstart=true, startwith = file})
local code = (
[[xpcall(function()
io.stdout:setvbuf('no')
require("mobdebug").moai() -- enable debugging for coroutines
%s
end, function(err) print(debug.traceback(err)) end)]]):format(rundebug)
local tmpfile = wx.wxFileName()
tmpfile:AssignTempFileName(".")
file = tmpfile:GetFullPath()
local f = io.open(file, "w")
if not f then
DisplayOutput("Can't open temporary file '"..file.."' for writing\n")
return
end
f:write(code)
f:close()
end
file = file or wfilename:GetFullPath()
-- try to find a config file: (1) MOAI_CONFIG, (2) project directory,
-- (3) folder with the current file, (4) folder with moai executable
local config = GetFullPathIfExists(os.getenv('MOAI_CONFIG') or self:fworkdir(wfilename), 'config.lua')
or GetFullPathIfExists(wfilename:GetPath(wx.wxPATH_GET_VOLUME), 'config.lua')
or GetFullPathIfExists(wx.wxFileName(moai):GetPath(wx.wxPATH_GET_VOLUME), 'config.lua')
local cmd = config and ('"%s" "%s" "%s"'):format(moai, config, file)
or ('"%s" "%s"'):format(moai, file)
-- CommandLineRun(cmd,wdir,tooutput,nohide,stringcallback,uid,endcallback)
return CommandLineRun(cmd,self:fworkdir(wfilename),true,false,nil,nil,
function() ide.debugger.pid = nil if rundebug then wx.wxRemoveFile(file) end end)
end,
fprojdir = function(self,wfilename)
return wfilename:GetPath(wx.wxPATH_GET_VOLUME)
end,
fworkdir = function(self,wfilename)
return ide.config.path.projectdir or wfilename:GetPath(wx.wxPATH_GET_VOLUME)
end,
hasdebugger = true,
fattachdebug = function(self) DebuggerAttachDefault() end,
scratchextloop = true,
}

View File

@@ -1,12 +1,12 @@
--
-- MobDebug 0.467
-- MobDebug 0.489
-- Copyright 2011-12 Paul Kulchenko
-- Based on RemDebug 1.0 Copyright Kepler Project 2005
--
local mobdebug = {
_NAME = "mobdebug",
_VERSION = 0.467,
_VERSION = 0.489,
_COPYRIGHT = "Paul Kulchenko",
_DESCRIPTION = "Mobile Remote Debugger for the Lua programming language",
port = 8171
@@ -24,6 +24,8 @@ local setmetatable = setmetatable
local string = string
local tonumber = tonumber
local mosync = mosync
local jit = jit
local moai = MOAISim
-- this is a socket class that implements maConnect interface
local function socketMobileLua()
@@ -188,7 +190,7 @@ local debugee = function ()
end
local serpent = (function() ---- include Serpent module for serialization
local n, v = "serpent", 0.15 -- (C) 2012 Paul Kulchenko; MIT License
local n, v = "serpent", 0.16 -- (C) 2012 Paul Kulchenko; MIT License
local c, d = "Paul Kulchenko", "Serializer and pretty printer of Lua data types"
local snum = {[tostring(1/0)]='1/0 --[[math.huge]]',[tostring(-1/0)]='-1/0 --[[-math.huge]]',[tostring(0/0)]='0/0'}
local badtype = {thread = true, userdata = true}
@@ -213,7 +215,7 @@ local function s(t, opts)
or ("%q"):format(s):gsub("\010","n"):gsub("\026","\\026") end
local function comment(s,l) return comm and (l or 0) < comm and ' --[['..tostring(s)..']]' or '' end
local function globerr(s,l) return globals[s] and globals[s]..comment(s,l) or not fatal
and safestr(tostring(s))..comment('err',l) or error("Can't serialize "..tostring(s)) end
and safestr(tostring(s)) or error("Can't serialize "..tostring(s)) end
local function safename(path, name) -- generates foo.bar, foo[3], or foo['b a r']
local n = name == nil and '' or name
local plain = type(n) == "string" and n:match("^[%l%u_][%w_]*$") and not keyword[n]
@@ -238,7 +240,7 @@ local function s(t, opts)
elseif ttype == 'function' then
seen[t] = spath
local ok, res = pcall(string.dump, t)
local func = ok and ((opts.nocode and "function() end" or
local func = ok and ((opts.nocode and "function() --[[..skipped..]] end" or
"loadstring("..safestr(res)..",'@serialized')")..comment(t, level))
return tag..(func or globerr(t, level))
elseif ttype == "table" then
@@ -333,23 +335,52 @@ local function remove_breakpoint(file, line)
end
end
-- moai host uses full path in source files whereas the standard lua
-- interpreter uses relative paths this debugger relies on.
-- to check if there is a breakpoint, do a string search (from the end)
-- to find a potentially matching breakpoint.
-- may have false positives, but good enough as only affects moai debugging.
local function has_breakpoint_moai(file, line)
for fname, lines in pairs(breakpoints) do
if #file > #fname and file:find('/'..fname, -#fname-1, true)
and lines[line] then return true end
end
return false
end
local function has_breakpoint(file, line)
return breakpoints[file] and breakpoints[file][line]
or moai and has_breakpoint_moai(file, line)
end
local function restore_vars(vars)
if type(vars) ~= 'table' then return end
local func = debug.getinfo(3, "f").func
-- locals need to be processed in the reverse order, starting from
-- the inner block out, to make sure that the localized variables
-- are correctly updated with only the closest variable with
-- the same name being changed
-- first loop find how many local variables there is, while
-- the second loop processes them from i to 1
local i = 1
local written_vars = {}
while true do
local name = debug.getlocal(3, i)
if not name then break end
if string.sub(name, 1, 1) ~= '(' then debug.setlocal(3, i, vars[name]) end
written_vars[name] = true
i = i + 1
end
i = i - 1
local written_vars = {}
while i > 0 do
local name = debug.getlocal(3, i)
if not written_vars[name] then
if string.sub(name, 1, 1) ~= '(' then debug.setlocal(3, i, vars[name]) end
written_vars[name] = true
end
i = i - 1
end
i = 1
local func = debug.getinfo(3, "f").func
while true do
local name = debug.getupvalue(func, i)
if not name then break end
@@ -417,7 +448,7 @@ end
local function debug_hook(event, line)
if abort and is_safe(stack_level) then error(abort) end
-- LuaJIT needs special treatment. Because debug_hook is set for
-- (1) LuaJIT needs special treatment. Because debug_hook is set for
-- *all* coroutines, and not just the one being debugged as in regular Lua
-- (http://lua-users.org/lists/lua-l/2011-06/msg00513.html),
-- need to avoid debugging mobdebug's own code as LuaJIT doesn't
@@ -427,7 +458,10 @@ local function debug_hook(event, line)
-- 'tail return' events are not generated by LuaJIT).
-- the next line checks if the debugger is run under LuaJIT and if
-- one of debugger methods is present in the stack, it simply returns.
if jit and in_debugger() then return end
-- (2) also check if this debug hook has not been visited for any reason.
-- this check is needed to avoid stepping in too early
-- (for example, when coroutine.resume() is executed inside start()).
if (jit or not seen_hook) and in_debugger() then return end
if event == "call" then
stack_level = stack_level + 1
@@ -442,13 +476,18 @@ local function debug_hook(event, line)
skipcount = 0
end
-- this is needed to check if the stack got shorter.
-- this may happen when "pcall(load, '')" is called
-- this is needed to check if the stack got shorter or longer.
-- unfortunately counting call/return calls is not reliable.
-- the discrepancy may happen when "pcall(load, '')" call is made
-- or when "error()" is called in a function.
-- in either case there are more "call" than "return" events reported.
-- this validation is done for every "line" event, but should be
-- "cheap" as it only checks for the stack to get shorter
stack_level = stack_depth(stack_level)
-- this validation is done for every "line" event, but should be "cheap"
-- as it checks for the stack to get shorter (or longer by one call).
-- start from one level higher just in case we need to grow the stack.
-- this may happen after coroutine.resume call to a function that doesn't
-- have any other instructions to execute. it triggers three returns:
-- "return, tail return, return", which needs to be accounted for.
stack_level = stack_depth(stack_level+1)
local caller = debug.getinfo(2, "S")
-- grab the filename and fix it if needed
@@ -467,46 +506,54 @@ local function debug_hook(event, line)
lastfile = file
end
local vars
local vars, status, res
if (watchescnt > 0) then
vars = capture_vars()
for index, value in pairs(watches) do
setfenv(value, vars)
local status, res = pcall(value)
if status and res then
coroutine.resume(coro_debugger, events.WATCH, vars, file, line, index)
local ok, fired = pcall(value)
if ok and fired then
status, res = coroutine.resume(coro_debugger, events.WATCH, vars, file, line, index)
break -- any one watch is enough; don't check multiple times
end
end
end
if step_into
or (step_over and stack_level <= step_level)
or has_breakpoint(file, line)
or (socket.select({server}, {}, 0))[server] then
-- need to get into the "regular" debug handler, but only if there was
-- no watch that was fired. If there was a watch, handle its result.
local getin = (status == nil) and
(step_into
or (step_over and stack_level <= step_level)
or has_breakpoint(file, line)
or (socket.select({server}, {}, 0))[server])
if getin then
vars = vars or capture_vars()
seen_hook = true
step_into = false
step_over = false
local status, res = coroutine.resume(coro_debugger, events.BREAK, vars, file, line)
-- handle 'stack' command that provides stack() information to the debugger
if status and res == 'stack' then
while status and res == 'stack' do
-- resume with the stack trace and variables
status, res = coroutine.resume(coro_debugger, events.STACK, stack(3), file, line)
end
end
-- need to recheck once more as resume after 'stack' command may
-- return something else (for example, 'exit'), which needs to be handled
if status and res and res ~= 'stack' then
if abort == nil and res == "exit" then os.exit(1) end
abort = res
-- only abort if safe; if not, there is another (earlier) check inside
-- debug_hook, which will abort execution at the first safe opportunity
if is_safe(stack_level) then error(abort) end
end -- abort execution if requested
status, res = coroutine.resume(coro_debugger, events.BREAK, vars, file, line)
end
-- handle 'stack' command that provides stack() information to the debugger
if status and res == 'stack' then
while status and res == 'stack' do
-- resume with the stack trace and variables
if vars then restore_vars(vars) end -- restore vars so they are reflected in stack values
status, res = coroutine.resume(coro_debugger, events.STACK, stack(3), file, line)
end
end
-- need to recheck once more as resume after 'stack' command may
-- return something else (for example, 'exit'), which needs to be handled
if status and res and res ~= 'stack' then
if abort == nil and res == "exit" then os.exit(1) end
abort = res
-- only abort if safe; if not, there is another (earlier) check inside
-- debug_hook, which will abort execution at the first safe opportunity
if is_safe(stack_level) then error(abort) end
end
if vars then restore_vars(vars) end
end
end
@@ -542,7 +589,8 @@ local function debugger_loop(sfile, sline)
app = app or (wx and wx.wxGetApp and wx.wxGetApp())
if app then
local win = app:GetTopWindow()
if win then
local inloop = app:IsMainLoopRunning()
if win and not inloop then
-- process messages in a regular way
-- and exit as soon as the event loop is idle
win:Connect(wx.wxEVT_IDLE, function()
@@ -559,7 +607,7 @@ local function debugger_loop(sfile, sline)
if server.settimeout then server:settimeout() end -- back to blocking
command = string.sub(line, string.find(line, "^[A-Z]+"))
if command == "SETB" then
local _, _, _, file, line = string.find(line, "^([A-Z]+)%s+([%w%p%s]+)%s+(%d+)%s*$")
local _, _, _, file, line = string.find(line, "^([A-Z]+)%s+(.-)%s+(%d+)%s*$")
if file and line then
set_breakpoint(file, tonumber(line))
server:send("200 OK\n")
@@ -567,7 +615,7 @@ local function debugger_loop(sfile, sline)
server:send("400 Bad Request\n")
end
elseif command == "DELB" then
local _, _, _, file, line = string.find(line, "^([A-Z]+)%s+([%w%p%s]+)%s+(%d+)%s*$")
local _, _, _, file, line = string.find(line, "^([A-Z]+)%s+(.-)%s+(%d+)%s*$")
if file and line then
remove_breakpoint(file, tonumber(line))
server:send("200 OK\n")
@@ -594,7 +642,7 @@ local function debugger_loop(sfile, sline)
server:send("400 Bad Request\n")
end
elseif command == "LOAD" then
local _, _, size, name = string.find(line, "^[A-Z]+%s+(%d+)%s+([%w%p%s]*[%w%p]+)%s*$")
local _, _, size, name = string.find(line, "^[A-Z]+%s+(%d+)%s+(%S.-)%s*$")
size = tonumber(size)
if abort == nil then -- no LOAD/RELOAD allowed inside start()
@@ -634,14 +682,15 @@ local function debugger_loop(sfile, sline)
elseif command == "SETW" then
local _, _, exp = string.find(line, "^[A-Z]+%s+(.+)%s*$")
if exp then
local func = loadstring("return(" .. exp .. ")")
local func, res = loadstring("return(" .. exp .. ")")
if func then
watchescnt = watchescnt + 1
local newidx = #watches + 1
watches[newidx] = func
server:send("200 OK " .. newidx .. "\n")
else
server:send("400 Bad Request\n")
server:send("401 Error in Expression " .. string.len(res) .. "\n")
server:send(res)
end
else
server:send("400 Bad Request\n")
@@ -754,7 +803,12 @@ local function start(controller_host, controller_port)
server = socket.connect(controller_host, controller_port)
if server then
-- check if we are called from the debugger as this may happen
-- when another debugger function calls start(); only check one level deep
local this = debug.getinfo(1, "S").source
local info = debug.getinfo(2, "Sl")
if info.source == this then info = debug.getinfo(3, "Sl") end
local file = info.source
if string.find(file, "@") == 1 then file = string.sub(file, 2) end
if string.find(file, "%.[/\\]") == 1 then file = string.sub(file, 3) end
@@ -765,14 +819,15 @@ local function start(controller_host, controller_port)
-- start from 16th frame, which is sufficiently large for this check.
stack_level = stack_depth(16)
debug.sethook(debug_hook, "lcr")
coro_debugger = coroutine.create(debugger_loop)
debug.sethook(debug_hook, "lcr")
return coroutine.resume(coro_debugger, file, info.currentline)
else
print("Could not connect to " .. controller_host .. ":" .. controller_port)
end
end
local coro_debugee
local function controller(controller_host, controller_port)
-- only one debugging session can be run (as there is only one debug hook)
if isrunning() then return end
@@ -790,14 +845,15 @@ local function controller(controller_host, controller_port)
return err
end
seen_hook = true -- allow to accept all commands
coro_debugger = coroutine.create(debugger_loop)
while true do
step_into = true
abort = false
if skip then skipcount = skip end -- to force suspend right away
while true do
step_into = true -- start with step command
abort = false -- reset abort flag from the previous loop
if skip then skipcount = skip end -- force suspend right away
local coro_debugee = coroutine.create(debugee)
coro_debugee = coroutine.create(debugee)
debug.sethook(coro_debugee, debug_hook, "lcr")
local status, err = coroutine.resume(coro_debugee)
@@ -819,7 +875,6 @@ local function controller(controller_host, controller_port)
end
end
end
server:close()
else
print("Could not connect to " .. controller_host .. ":" .. controller_port)
return false
@@ -837,7 +892,37 @@ local function loop(controller_host, controller_port)
return controller(controller_host, controller_port)
end
local coroutines = {}
setmetatable(coroutines, {__mode = "k"}) -- "weak" keys
local function on()
if not (isrunning() and server) then return end
local co = coroutine.running()
if co then
if not coroutines[co] then
coroutines[co] = true
debug.sethook(co, debug_hook, "lcr")
end
else
debug.sethook(debug_hook, "lcr")
end
end
local function off()
if not (isrunning() and server) then return end
local co = coroutine.running()
if co then
if coroutines[co] then coroutines[co] = false end
debug.sethook(co)
else
debug.sethook()
end
end
local basedir = ""
local function q(s) return s:gsub('([%(%)%.%%%+%-%*%?%[%^%$%]])','%%%1') end
-- Handles server debugging commands
local function handle(params, client)
@@ -857,12 +942,12 @@ local function handle(params, client)
if status == "200" then
-- don't need to do anything
elseif status == "202" then
_, _, file, line = string.find(breakpoint, "^202 Paused%s+([%w%p%s]+)%s+(%d+)%s*$")
_, _, file, line = string.find(breakpoint, "^202 Paused%s+(.-)%s+(%d+)%s*$")
if file and line then
print("Paused at file " .. file .. " line " .. line)
end
elseif status == "203" then
_, _, file, line, watch_idx = string.find(breakpoint, "^203 Paused%s+([%w%p%s]+)%s+(%d+)%s+(%d+)%s*$")
_, _, file, line, watch_idx = string.find(breakpoint, "^203 Paused%s+(.-)%s+(%d+)%s+(%d+)%s*$")
if file and line and watch_idx then
print("Paused at file " .. file .. " line " .. line .. " (watch expression " .. watch_idx .. ": [" .. watches[watch_idx] .. "])")
end
@@ -881,10 +966,10 @@ local function handle(params, client)
return nil, nil, "Debugger error: unexpected response '" .. breakpoint .. "'"
end
elseif command == "setb" then
_, _, _, file, line = string.find(params, "^([a-z]+)%s+([%w%p%s]+)%s+(%d+)%s*$")
_, _, _, file, line = string.find(params, "^([a-z]+)%s+(.-)%s+(%d+)%s*$")
if file and line then
file = string.gsub(file, "\\", "/") -- convert slash
file = string.gsub(file, basedir, '') -- remove basedir
file = string.gsub(file, q(basedir), '') -- remove basedir
if not breakpoints[file] then breakpoints[file] = {} end
client:send("SETB " .. file .. " " .. line .. "\n")
if client:receive() == "200 OK" then
@@ -905,16 +990,22 @@ local function handle(params, client)
watches[watch_idx] = exp
print("Inserted watch exp no. " .. watch_idx)
else
print("Error: Watch expression not inserted")
local _, _, size = string.find(answer, "^401 Error in Expression (%d+)$")
if size then
local err = client:receive(tonumber(size)):gsub(".-:%d+:%s*","")
print("Error: watch expression not set: " .. err)
else
print("Error: watch expression not set")
end
end
else
print("Invalid command")
end
elseif command == "delb" then
_, _, _, file, line = string.find(params, "^([a-z]+)%s+([%w%p%s]+)%s+(%d+)%s*$")
_, _, _, file, line = string.find(params, "^([a-z]+)%s+(.-)%s+(%d+)%s*$")
if file and line then
file = string.gsub(file, "\\", "/") -- convert slash
file = string.gsub(file, basedir, '') -- remove basedir
file = string.gsub(file, q(basedir), '') -- remove basedir
if not breakpoints[file] then breakpoints[file] = {} end
client:send("DELB " .. file .. " " .. line .. "\n")
if client:receive() == "200 OK" then
@@ -979,12 +1070,19 @@ local function handle(params, client)
client:send(lines)
else
local file = io.open(exp, "r")
if not file then print("Cannot open file " .. exp); return end
local lines = file:read("*all")
if not file and pcall(require, "winapi") then
-- if file is not open and winapi is there, try with a short path;
-- this may be needed for unicode paths on windows
winapi.set_encoding(winapi.CP_UTF8)
file = io.open(winapi.short_path(exp), "r")
end
if not file then error("Cannot open file " .. exp) end
-- read the file and remove the shebang line as it causes a compilation error
local lines = file:read("*all"):gsub("^#!.-\n", "\n")
file:close()
local file = string.gsub(exp, "\\", "/") -- convert slash
file = string.gsub(file, basedir, '') -- remove basedir
file = string.gsub(file, q(basedir), '') -- remove basedir
client:send("LOAD " .. string.len(lines) .. " " .. file .. "\n")
client:send(lines)
end
@@ -992,7 +1090,7 @@ local function handle(params, client)
if not params then
return nil, nil, "Debugger error: missing response after EXEC/LOAD"
end
local _, _, status, len = string.find(params, "^(%d+)[%w%p%s]+%s+(%d+)%s*$")
local _, _, status, len = string.find(params, "^(%d+).-%s+(%d+)%s*$")
if status == "200" then
len = tonumber(len)
if len > 0 then
@@ -1015,7 +1113,7 @@ local function handle(params, client)
return res[1], res
end
elseif status == "201" then
_, _, file, line = string.find(params, "^201 Started%s+([%w%p%s]+)%s+(%d+)%s*$")
_, _, file, line = string.find(params, "^201 Started%s+(.-)%s+(%d+)%s*$")
elseif status == "202" or params == "200 OK" then
-- do nothing; this only happens when RE/LOAD command gets the response
-- that was for the original command that was aborted
@@ -1061,7 +1159,7 @@ local function handle(params, client)
local src = string.gsub(frame[1][2], "\\", "/") -- convert slash
if string.find(src, "@") == 1 then src = string.sub(src, 2) end
if string.find(src, "%./") == 1 then src = string.sub(src, 3) end
frame[1][2] = string.gsub(src, basedir, '') -- remove basedir
frame[1][2] = string.gsub(src, q(basedir), '') -- remove basedir
print(serpent.line(frame[1], {comment = false}))
end
return stack
@@ -1130,7 +1228,7 @@ local function listen(host, port)
client:receive()
local breakpoint = client:receive()
local _, _, file, line = string.find(breakpoint, "^202 Paused%s+([%w%p%s]+)%s+(%d+)%s*$")
local _, _, file, line = string.find(breakpoint, "^202 Paused%s+(.-)%s+(%d+)%s*$")
if file and line then
print("Paused at file " .. file )
print("Type 'help' for commands")
@@ -1149,6 +1247,37 @@ local function listen(host, port)
end
end
local cocreate
local function coro()
if cocreate then return end -- only set once
cocreate = cocreate or coroutine.create
coroutine.create = function(f, ...)
return cocreate(function(...)
require("mobdebug").on()
return f(...)
end, ...)
end
end
local moconew
local function moai()
if moconew then return end -- only set once
moconew = moconew or (MOAICoroutine and MOAICoroutine.new)
if not moconew then return end
MOAICoroutine.new = function(...)
local thread = moconew(...)
local mt = getmetatable(thread)
local patched = mt.run
mt.run = function(self, f, ...)
return patched(self, function(...)
require("mobdebug").on()
return f(...)
end, ...)
end
return thread
end
end
-- make public functions available
mobdebug.listen = listen
mobdebug.loop = loop
@@ -1156,6 +1285,10 @@ mobdebug.scratchpad = scratchpad
mobdebug.handle = handle
mobdebug.connect = connect
mobdebug.start = start
mobdebug.on = on
mobdebug.off = off
mobdebug.moai = moai
mobdebug.coro = coro
mobdebug.line = serpent.line
mobdebug.dump = serpent.dump

315
lualibs/testwell.lua Normal file
View File

@@ -0,0 +1,315 @@
--
-- Copyright (C) 2012 Paul Kulchenko
-- A simple testing library
-- Based on lua-TestMore : <http://fperrad.github.com/lua-TestMore/>
-- Copyright (c) 2009-2011 Francois Perrad
-- This library is licensed under the terms of the MIT/X11 license,
-- like Lua itself.
--
local pairs = pairs
local tostring = tostring
local type = type
local _G = _G or _ENV
-----------------------------------------------------------
local tb = {
curr_test = 0,
good_test = 0,
skip_test = 0,
}
function tb:print(...)
print(...)
end
function tb:note(...)
self:print(...)
end
function tb:diag(...)
local arg = {...}
for k, v in pairs(arg) do
arg[k] = tostring(v)
end
local msg = table.concat(arg)
msg = msg:gsub("\n", "\n# ")
msg = msg:gsub("\n# \n", "\n#\n")
msg = msg:gsub("\n# $", '')
self:print("# " .. msg)
end
function tb:ok(test, name, more)
self.curr_test = self.curr_test + 1
self.good_test = self.good_test + (test and 1 or 0)
self.skip_test = self.skip_test + (test == nil and 1 or 0)
name = tostring(name or '')
local out = ''
if not test then
out = "not "
end
out = out .. "ok " .. self.curr_test
if name ~= '' then
out = out .. " - " .. name
end
self:print(out)
if test == false then
self:diag(" Failed test " .. (name and ("'" .. name .. "'") or ''))
if debug then
local info = debug.getinfo(3)
local file = info.short_src
local line = info.currentline
self:diag(" in " .. file .. " at line " .. line .. ".")
end
self:diag(more)
end
end
function tb:done_testing(reset)
local c, g, s = self.curr_test, self.good_test, self.skip_test
if reset then
self.curr_test = 0
self.good_test = 0
self.skip_test = 0
end
return c, g, s
end
-----------------------------------------------------------
local serpent = (function() ---- include Serpent module for serialization
local n, v = "serpent", 0.15 -- (C) 2012 Paul Kulchenko; MIT License
local c, d = "Paul Kulchenko", "Serializer and pretty printer of Lua data types"
local snum = {[tostring(1/0)]='1/0 --[[math.huge]]',[tostring(-1/0)]='-1/0 --[[-math.huge]]',[tostring(0/0)]='0/0'}
local badtype = {thread = true, userdata = true}
local keyword, globals, G = {}, {}, (_G or _ENV)
for _,k in ipairs({'and', 'break', 'do', 'else', 'elseif', 'end', 'false',
'for', 'function', 'goto', 'if', 'in', 'local', 'nil', 'not', 'or', 'repeat',
'return', 'then', 'true', 'until', 'while'}) do keyword[k] = true end
for k,v in pairs(G) do globals[v] = k end -- build func to name mapping
for _,g in ipairs({'coroutine', 'debug', 'io', 'math', 'string', 'table', 'os'}) do
for k,v in pairs(G[g]) do globals[v] = g..'.'..k end end
local function s(t, opts)
local name, indent, fatal = opts.name, opts.indent, opts.fatal
local sparse, custom, huge = opts.sparse, opts.custom, not opts.nohuge
local space, maxl = (opts.compact and '' or ' '), (opts.maxlevel or math.huge)
local comm = opts.comment and (tonumber(opts.comment) or math.huge)
local seen, sref, syms, symn = {}, {}, {}, 0
local function gensym(val) return tostring(val):gsub("[^%w]",""):gsub("(%d%w+)",
function(s) if not syms[s] then symn = symn+1; syms[s] = symn end return syms[s] end) end
local function safestr(s) return type(s) == "number" and (huge and snum[tostring(s)] or s)
or type(s) ~= "string" and tostring(s) -- escape NEWLINE/010 and EOF/026
or ("%q"):format(s):gsub("\010","n"):gsub("\026","\\026") end
local function comment(s,l) return comm and (l or 0) < comm and ' --[['..tostring(s)..']]' or '' end
local function globerr(s,l) return globals[s] and globals[s]..comment(s,l) or not fatal
and safestr(tostring(s))..comment('err',l) or error("Can't serialize "..tostring(s)) end
local function safename(path, name) -- generates foo.bar, foo[3], or foo['b a r']
local n = name == nil and '' or name
local plain = type(n) == "string" and n:match("^[%l%u_][%w_]*$") and not keyword[n]
local safe = plain and n or '['..safestr(n)..']'
return (path or '')..(plain and path and '.' or '')..safe, safe end
local alphanumsort = type(opts.sortkeys) == 'function' and opts.sortkeys or function(o, n)
local maxn, to = tonumber(n) or 12, {number = 'a', string = 'b'}
local function padnum(d) return ("%0"..maxn.."d"):format(d) end
table.sort(o, function(a,b)
return (o[a] and 0 or to[type(a)] or 'z')..(tostring(a):gsub("%d+",padnum))
< (o[b] and 0 or to[type(b)] or 'z')..(tostring(b):gsub("%d+",padnum)) end) end
local function val2str(t, name, indent, path, plainindex, level)
local ttype, level = type(t), (level or 0)
local spath, sname = safename(path, name)
local tag = plainindex and
((type(name) == "number") and '' or name..space..'='..space) or
(name ~= nil and sname..space..'='..space or '')
if seen[t] then
table.insert(sref, spath..space..'='..space..seen[t])
return tag..'nil'..comment('ref', level)
elseif badtype[ttype] then return tag..globerr(t, level)
elseif ttype == 'function' then
seen[t] = spath
local ok, res = pcall(string.dump, t)
local func = ok and ((opts.nocode and "function() end" or
"loadstring("..safestr(res)..",'@serialized')")..comment(t, level))
return tag..(func or globerr(t, level))
elseif ttype == "table" then
if level >= maxl then return tag..'{}'..comment('max', level) end
seen[t] = spath
if next(t) == nil then return tag..'{}'..comment(t, level) end -- table empty
local maxn, o, out = #t, {}, {}
for key = 1, maxn do table.insert(o, key) end
for key in pairs(t) do if not o[key] then table.insert(o, key) end end
if opts.sortkeys then alphanumsort(o, opts.sortkeys) end
for n, key in ipairs(o) do
local value, ktype, plainindex = t[key], type(key), n <= maxn and not sparse
if opts.ignore and opts.ignore[value] -- skip ignored values; do nothing
or sparse and value == nil then -- skipping nils; do nothing
elseif ktype == 'table' or ktype == 'function' then
if not seen[key] and not globals[key] then
table.insert(sref, 'local '..val2str(key,gensym(key),indent)) end
table.insert(sref, seen[t]..'['..(seen[key] or globals[key] or gensym(key))
..']'..space..'='..space..(seen[value] or val2str(value,nil,indent)))
else
if badtype[ktype] then plainindex, key = true, '['..globerr(key, level+1)..']' end
table.insert(out,val2str(value,key,indent,spath,plainindex,level+1))
end
end
local prefix = string.rep(indent or '', level)
local head = indent and '{\n'..prefix..indent or '{'
local body = table.concat(out, ','..(indent and '\n'..prefix..indent or space))
local tail = indent and "\n"..prefix..'}' or '}'
return (custom and custom(tag,head,body,tail) or tag..head..body..tail)..comment(t, level)
else return tag..safestr(t) end -- handle all other types
end
local sepr = indent and "\n" or ";"..space
local body = val2str(t, name, indent) -- this call also populates sref
local tail = #sref>0 and table.concat(sref, sepr)..sepr or ''
return not name and body or "do local "..body..sepr..tail.."return "..name..sepr.."end"
end
local function merge(a, b) if b then for k,v in pairs(b) do a[k] = v end end; return a; end
return { _NAME = n, _COPYRIGHT = c, _DESCRIPTION = d, _VERSION = v, serialize = s,
dump = function(a, opts) return s(a, merge({name = '_', compact = true, sparse = true}, opts)) end,
line = function(a, opts) return s(a, merge({sortkeys = true, comment = true}, opts)) end,
block = function(a, opts) return s(a, merge({indent = ' ', sortkeys = true, comment = true}, opts)) end }
end)() ---- end of Serpent module
-----------------------------------------------------------
local m = {}
function m.ok(test, name)
tb:ok(test, name)
end
local parms = {comment = false}
function m.is(got, expected, name)
local tgot, texp = type(got), type(expected)
local vgot, vexp = serpent.line(got, parms), serpent.line(expected, parms)
local pass = vgot == vexp
if got == nil then pass = nil end
tb:ok(pass, name, not pass and
" got: " .. vgot .. " (" .. tgot .. ")" ..
"\n expected: " .. vexp .. " (" .. texp .. ")")
end
function m.isnt(got, expected, name)
local tgot, texp = type(got), type(expected)
local vgot, vexp = serpent.line(got, parms), serpent.line(expected, parms)
local pass = vgot ~= vexp
if got == nil then pass = nil end
tb:ok(pass, name, not pass and
" got: " .. vgot .. " (" .. tgot .. ")" ..
"\n expected: anything else")
end
function m.like(got, pattern, name)
if type(pattern) ~= 'string' then
return tb:ok(false, name, "pattern isn't a string : " .. tostring(pattern))
end
local pass = tostring(got):match(pattern)
if got == nil then pass = nil end
tb:ok(pass, name, not pass and
" '" .. tostring(got) .. "'" ..
"\n doesn't match '" .. pattern .. "'")
end
function m.unlike(got, pattern, name)
if type(pattern) ~= 'string' then
return tb:ok(false, name, "pattern isn't a string : " .. tostring(pattern))
end
local pass = not tostring(got):match(pattern)
if got == nil then pass = nil end
tb:ok(pass, name, not pass and
" '" .. tostring(got) .. "'" ..
"\n matches '" .. pattern .. "'")
end
local cmp = {
['<'] = function (a, b) return a < b end,
['<='] = function (a, b) return a <= b end,
['>'] = function (a, b) return a > b end,
['>='] = function (a, b) return a >= b end,
['=='] = function (a, b) return a == b end,
['~='] = function (a, b) return a ~= b end,
}
function m.cmp_ok(this, op, that, name)
local f = cmp[op]
if not f then
return tb:ok(false, name, "unknown operator : " .. tostring(op))
end
local pass = f(this, that)
if this == nil then pass = nil end
tb:ok(pass, name, not pass and
" " .. tostring(this) ..
"\n " .. op ..
"\n " .. tostring(that))
end
function m.type_ok(val, t, name)
if type(t) ~= 'string' then
return tb:ok(false, name, "type isn't a string : " .. tostring(t))
end
if type(val) == t then
tb:ok(true, name)
else
tb:ok(false, name,
" " .. tostring(val) .. " isn't a '" .. t .."', it's a '" .. type(val) .. "'")
end
end
function m.diag(...)
tb:diag(...)
end
function m.report()
local total, good, skipped = tb:done_testing(true)
if total == 0 then return end
local failed = total - good - skipped
local sum = ("(%d/%d/%d)."):format(good, skipped, total)
local num, msg = 0, ""
if good > 0 then
num, msg = good, msg .. "passed " .. good
end
if failed > 0 then
num, msg = failed, msg .. (#msg > 0 and (skipped > 0 and ", " or " and ") or "")
.. "failed " .. failed
end
if skipped > 0 then
num, msg = skipped, msg .. (#msg > 0 and ((good > 0 and failed > 0 and ',' or '') .." and ") or "")
.. "skipped " .. skipped
end
msg = ("Looks like you %s test%s of %d %s"):format(msg, (num > 1 and 's' or ''), total, sum)
if skipped == total then msg = "Looks like you skipped all tests " .. sum end
if good == total then msg = "All tests passed " .. sum end
tb:note(("1..%d # %s"):format(total, msg))
end
function m.ismain()
for l = 3, 64 do -- only check up to 64 level; no more needed
local info = debug.getinfo(l)
if not info then return true end
if info.func == require then return false end
end
return true
end
-- this is needed to call report() when the test object is destroyed
if _VERSION >= "Lua 5.2" then
setmetatable(m, {__gc = m.report})
else
-- keep sentinel alive until 'm' is garbage collected
m.sentinel = newproxy(true)
getmetatable(m.sentinel).__gc = m.report
end
for k, v in pairs(m) do -- injection
_G[k] = v
end
return m

View File

@@ -46,7 +46,7 @@ return {
},
keywords = {
[[int uint half float bool double
[[int uint half float bool double atomic_uint binding offset
vec2 vec3 vec4 dvec2 dvec3 dvec4
ivec2 ivec3 ivec4 uvec2 uvec3 uvec4 bvec2 bvec3 bvec4
mat2 mat3 mat4 mat2x2 mat3x3 mat4x4 mat2x3 mat3x2 mat4x2 mat2x4 mat4x3 mat3x4
@@ -63,8 +63,8 @@ return {
triangles quads equal_spacing isolines fractional_even_spacing lines points
fractional_odd_spacing cw ccw point_mode lines_adjacency triangles_adjacency
invocations
origin_upper_left pixel_center_integer
smooth flat noperspective highp mediump lowp shared packed std140 row_major column_major
origin_upper_left pixel_center_integer depth_greater depth_greater depth_greater depth_unchanged
smooth flat noperspective highp mediump lowp shared packed std140 std430 row_major column_major buffer
gl_FrontColor gl_BackColor gl_FrontSecondaryColor gl_BackSecondaryColor gl_Color gl_SecondaryColor
subroutine gl_Position gl_FragCoord
gl_VertexID gl_InstanceID gl_Normal gl_Vertex gl_MultiTexCoord0 gl_MultiTexCoord1
@@ -76,22 +76,26 @@ return {
gl_InvocationID gl_PrimitiveIDIn gl_Layer gl_ViewportIndex gl_FrontFacing
gl_PointCoord gl_SampleID gl_SamplePosition gl_FragColor
gl_FragData gl_FragDepth gl_SampleMask
gl_NumWorkGroups gl_WorkGroupSize gl_WorkGroupID gl_LocalInvocationID gl_GlobalInvocationID gl_LocalInvocationIndex
local_size_x local_size_y local_size_z
coherent volatile restrict
coherent volatile restrict readonly writeonly
image1D image2D image3D image2DRect imageCube imageBuffer image1DArray image2DArray imageCubeArray image2DMS image2DMSArray
uimage1D uimage2D uimage3D uimage2DRect uimageCube uimageBuffer uimage1DArray uimage2DArray uimageCubeArray uimage2DMS uimage2DMSArray
iimage1D iimage2D iimage3D iimage2DRect iimageCube iimageBuffer iimage1DArray iimage2DArray iimageCubeArray iimage2DMS iimage2DMSArray
size1x8 size1x16 size1x32 size2x32 size4x32
size1x8 size1x16 size1x32 size2x32 size4x32 rgba32f rgba16f rg32f rg16f r32f r16f rgba8 rgba16 r11f_g11f_b10f rgb10_a2ui
rgb10_a2i rg16 rg8 r16 r8 rgba32i rgba16i rgba8i rg32i rg16i rg8i r32i r16i r8i rgba32ui rgba16ui rgba8ui rg32ui rg16ui rg8ui
r32ui r16ui r8ui rgba16_snorm rgba8_snorm rg16_snorm rg8_snorm r16_snorm r8_snorm
]],
[[discard
radians degrees sin cos tan asin acos atan sinh cosh tanh asinh acosh atanh
pow exp log exp2 log2 sqrt inversesqrt abs sign floor trunc round
roundEven ceil fract mod modf min max mix step isnan isinf clamp smoothstep
floatBitsToInt intBitsToFloat uintBitsToFloat fma frexp ldexp
floatBitsToInt floatBitsToUint intBitsToFloat uintBitsToFloat fma frexp ldexp
packUnorm2x16 packUnorm4x8 packSnorm4x8
unpackUnorm2x16 unpackUnorm4x8 unpackSnorm4x8
packDouble2x32 unpackDouble2x32
packDouble2x32 unpackDouble2x32 packHalf2x16 unpackHalf2x16
length distance dot cross normalize ftransform faceforward
reflect refract
matrixCompMult outerProduct transpose determinant inverse
@@ -138,7 +142,12 @@ return {
imageAtomicAdd imageAtomicMin imageAtomicMax
imageAtomicIncWrap imageAtomicDecWrap imageAtomicAnd
imageAtomicOr imageAtomixXor imageAtomicExchange
imageCompSwap memoryBarrier
imageCompSwap
memoryBarrier groupMemoryBarrier memoryBarrierAtomicCounter memoryBarrierShared memoryBarrierBuffer memoryBarrierImage
atomicCounterIncrement atomicCounterDecrement atomicCounter
atomicMin atomicMax atomicAdd atomicAnd atomicOr atomicXor atomicExchange atomicCompSwap
x y z w
xxxx xxxy xxxz xxxw xxyx xxyy xxyz xxyw xxzx xxzy

View File

@@ -1,30 +1,27 @@
-- authors: Luxinia Dev (Eike Decker & Christoph Kubisch)
---------------------------------------------------------
local funcdef = "([A-Za-z_][A-Za-z0-9_%.%:]*)%s*"
local funccall = "([A-Za-z_][A-Za-z0-9_]*)%s*"
return {
exts = {"lua"},
exts = {"lua", "rockspec"},
lexer = wxstc.wxSTC_LEX_LUA,
apitype = "lua",
linecomment = "--",
sep = "%.:",
isfncall = function(str)
return string.find(str,"([A-Za-z0-9_]+)%s*%(")
return string.find(str, funccall .. "%(")
end,
isfndef = function(str)
local l
local s,e,cap,par = string.find(str,"function%s+([A-Za-z0-9_]+%s-[%.%:]?%s-[A-Za-z0-9_]*)%s*(%(.-%))")
local s,e,cap,par = string.find(str, "function%s+" .. funcdef .. "(%(.-%))")
-- try to match without brackets now, but only at the beginning of the line
if (not s) then
s,e,cap = string.find(str,"^%s*function%s+([A-Za-z0-9_]+%s-[%.%:]?%s-[A-Za-z0-9_]*)%s*")
s,e,cap = string.find(str, "^%s*function%s+" .. funcdef)
end
-- try to match "foo = function()"
if (not s) then
s,e,cap,cap1,cap2,par = string.find(str,"(([A-Za-z0-9_]+%s-[%.%:]?%s-)([A-Za-z0-9_]*))%s*=%s*function%s*(%(.-%))")
-- check if we captured 'local foo =' instead of 'foo.bar ='
if cap1 and cap2 and string.len(cap2) > 0 and not string.find(cap1,'[%.%:]') then
cap = cap2
s = s + string.len(cap1)
end
s,e,cap,par = string.find(str, funcdef .. "=%s*function%s*(%(.-%))")
end
if (s) then
l = string.find(string.sub(str,1,s-1),"local%s+$")

View File

@@ -112,6 +112,12 @@ config = {
whitespace = false,
autotabs = true, -- if true test for tabs after file load,
-- sets "usetabs" to true for this file
calltipdelay = nil, -- delay to show calltip (in ms)
},
default = {
name = 'untitled',
fullname = 'untitled.lua',
},
debugger = {
@@ -168,7 +174,7 @@ config = {
-- UDP port for single instance communication
activateoutput = false, -- activate output/console on Run/Debug/Compile
unhidewxwindow = false, -- try to unhide a wx window
unhidewindow = false, -- to unhide a gui window
allowinteractivescript = false, -- allow interaction in the output window
}
@@ -301,21 +307,18 @@ debuginterface = {
breakpoint = function(self,file,line,state) end, -- set breakpoint state
-- returns result table if successful
evaluate = function(self, expressions, fnSetValues) end, -- for watches tables expected
-- NYI getstack = function(self, fnSetValues ) end, -- get stack information
evaluate = function(self, expressions, fnSetValues) end, -- for watches tables
stack = function(self) end, -- get stack information
}
-- interpreter definition-- ----------------------------------------------------
interpreter = {
name = "",
description = "",
api = {"apifile_without_extension"} -- optional to limit loaded lua apis
frun = function(self,wfilename,withdebugger)
end,
fprojdir = function(self,wfilename)
return "projpath_from_filename" -- optional
end,
fattachdebug = function(self) end, -- optional
api = {"apifile_without_extension"} -- (opt) to limit loaded lua apis
frun = function(self,wfilename,withdebugger) end,
fprojdir = function(self,wfilename) return "projpath_from_filename" end, -- (opt)
fattachdebug = function(self) end, -- (opt)
hasdebugger = false, -- if debugging is available
scratchextloop = false, -- (opt) if scratchpad requires handling for external loop
}

View File

@@ -89,8 +89,8 @@ local function addAPI(apifile,only,subapis,known) -- relative to API directory
end
local function loadallAPIs (only,subapis,known)
for i,dir in ipairs(FileSysGet(".\\api\\*.*",wx.wxDIR)) do
local files = FileSysGet(dir.."\\*.*",wx.wxFILE)
for i,dir in ipairs(FileSysGet("./api/*",wx.wxDIR)) do
local files = FileSysGet(dir.."/*.*",wx.wxFILE)
for i,file in ipairs(files) do
if file:match "%.lua$" then
addAPI(file,only,subapis,known)

View File

@@ -8,7 +8,7 @@ local openDocuments = ide.openDocuments
local uimgr = frame.uimgr
function NewFile(event)
local editor = CreateEditor("untitled.lua")
local editor = CreateEditor(ide.config.default.fullname)
SetupKeywords(editor, "lua")
end
@@ -27,29 +27,24 @@ local function findDocumentToReuse()
end
function LoadFile(filePath, editor, file_must_exist)
filePath = wx.wxFileName(filePath):GetFullPath()
local cmpName = string.lower(string.gsub(filePath, "\\", "/"))
-- prevent files from being reopened again
if (not editor) then
local filePath = wx.wxFileName(filePath)
for id, doc in pairs(openDocuments) do
local docName = doc.filePath and string.lower(string.gsub(doc.filePath, "\\", "/"))
if cmpName == docName then
if doc.filePath and filePath:SameAs(wx.wxFileName(doc.filePath)) then
notebook:SetSelection(doc.index)
return doc.editor
end
end
end
filePath = wx.wxFileName(filePath):GetFullPath()
-- if not opened yet, try open now
local file_text = ""
local handle = io.open(filePath, "rb")
if handle then
file_text = handle:read("*a")
local file_text = FileRead(filePath)
if file_text then
if GetConfigIOFilter("input") then
file_text = GetConfigIOFilter("input")(filePath,file_text)
end
handle:close()
elseif file_must_exist then
return nil
end
@@ -57,7 +52,8 @@ function LoadFile(filePath, editor, file_must_exist)
local current = editor and editor:GetCurrentPos()
editor = editor
or findDocumentToReuse()
or CreateEditor(wx.wxFileName(filePath):GetFullName() or "untitled.lua")
or CreateEditor(wx.wxFileName(filePath):GetFullName()
or ide.config.default.fullname)
editor:Clear()
editor:ClearAll()
@@ -82,7 +78,7 @@ function LoadFile(filePath, editor, file_must_exist)
IndicateFunctions(editor)
SettingsAppendFileToHistory(filePath)
-- activate the editor; this is needed for those cases when the editor is
-- created from some other element, for example, from a project tree.
SetEditorSelection()
@@ -115,7 +111,7 @@ function OpenFile(event)
"",
"",
exts,
wx.wxOPEN + wx.wxFILE_MUST_EXIST)
wx.wxFD_OPEN + wx.wxFD_FILE_MUST_EXIST)
if fileDialog:ShowModal() == wx.wxID_OK then
if not LoadFile(fileDialog:GetPath(), nil, true) then
wx.wxMessageBox("Unable to load file '"..fileDialog:GetPath().."'.",
@@ -131,22 +127,15 @@ function SaveFile(editor, filePath)
if not filePath then
return SaveFileAs(editor)
else
if (ide.config.savebak) then
local backPath = filePath..".bak"
os.remove(backPath)
os.rename(filePath, backPath)
if (ide.config.savebak) then FileRename(filePath, filePath..".bak") end
local st = editor:GetText()
if GetConfigIOFilter("output") then
st = GetConfigIOFilter("output")(filePath,st)
end
local handle = io.open(filePath, "wb")
if handle then
local st = editor:GetText()
if GetConfigIOFilter("output") then
st = GetConfigIOFilter("output")(filePath,st)
end
handle:write(st)
handle:close()
--editor:EmptyUndoBuffer()
local ok, err = FileWrite(filePath, st)
if ok then
editor:SetSavePoint()
local id = editor:GetId()
openDocuments[id].filePath = filePath
@@ -155,9 +144,9 @@ function SaveFile(editor, filePath)
SetDocumentModified(id, false)
return true
else
wx.wxMessageBox("Unable to save file '"..filePath.."'.",
wx.wxMessageBox("Unable to save file '"..filePath.."': "..err,
"Error",
wx.wxOK + wx.wxCENTRE, ide.frame)
wx.wxICON_ERROR + wx.wxOK + wx.wxCENTRE, ide.frame)
end
end
@@ -170,7 +159,7 @@ function SaveFileAs(editor)
local filePath = openDocuments[id].filePath
if (not filePath) then
filePath = FileTreeGetDir()
filePath = (filePath or "").."untitled"
filePath = (filePath or "")..ide.config.default.name
end
local fn = wx.wxFileName(filePath)
@@ -182,12 +171,15 @@ function SaveFileAs(editor)
fn:GetPath(wx.wxPATH_GET_VOLUME),
fn:GetFullName(),
exts,
wx.wxSAVE)
wx.wxFD_SAVE)
if fileDialog:ShowModal() == wx.wxID_OK then
local filePath = fileDialog:GetPath()
if SaveFile(editor, filePath) then
SetEditorSelection() -- update title of the editor
FileTreeRefresh() -- refresh the tree to reflect the new file
FileTreeMarkSelected(filePath)
SetupKeywords(editor, GetFileExt(filePath))
IndicateFunctions(editor)
if MarkupStyle then MarkupStyle(editor) end
@@ -288,7 +280,8 @@ function SaveModifiedDialog(editor, allow_cancel)
local filePath = document.filePath
local fileName = document.fileName
if document.isModified then
local message = "Do you want to save the changes to '"..(fileName or 'untitled').."'?"
local message = "Do you want to save the changes to '"
..(fileName or ide.config.default.name).."'?"
local dlg_styles = wx.wxYES_NO + wx.wxCENTRE + wx.wxICON_QUESTION
if allow_cancel then dlg_styles = dlg_styles + wx.wxCANCEL end
local dialog = wx.wxMessageDialog(ide.frame, message,
@@ -311,8 +304,13 @@ function SaveOnExit(allow_cancel)
if (SaveModifiedDialog(document.editor, allow_cancel) == wx.wxID_CANCEL) then
return false
end
end
document.isModified = false
-- if all documents have been saved or refused to save, then mark those that
-- are still modified as not modified (they don't need to be saved)
-- to keep their tab names correct
for id, document in pairs(openDocuments) do
if document.isModified then SetDocumentModified(id, false) end
end
return true
@@ -398,7 +396,10 @@ function ClearAllCurrentLineMarkers()
end
function CompileProgram(editor, quiet)
local editorText = editor:GetText()
-- remove shebang line (#!) as it throws a compilation error as
-- loadstring() doesn't allow it even though lua/loadfile accepts it.
-- replace with a new line to keep the number of lines the same.
local editorText = editor:GetText():gsub("^#!.-\n", "\n")
local id = editor:GetId()
local filePath = DebuggerMakeFileName(editor, openDocuments[id].filePath)
local _, errMsg, line_num = wxlua.CompileLuaScript(editorText, filePath)
@@ -496,7 +497,8 @@ function ShowFullScreen(setFullScreen)
uimgr:GetPane("toolBar"):Show(not setFullScreen)
uimgr:Update()
frame:ShowFullScreen(setFullScreen)
-- protect from systems that don't have ShowFullScreen (GTK on linux?)
pcall(function() frame:ShowFullScreen(setFullScreen) end)
end
function CloseWindow(event)
@@ -514,10 +516,14 @@ function CloseWindow(event)
SettingsSaveView()
SettingsSaveFramePosition(ide.frame, "MainFrame")
SettingsSaveEditorSettings()
DebuggerCloseWatchWindow()
DebuggerCloseStackWindow()
DebuggerShutdown()
if DebuggerCloseWatchWindow then DebuggerCloseWatchWindow() end
if DebuggerCloseStackWindow then DebuggerCloseStackWindow() end
if DebuggerShutdown then DebuggerShutdown() end
ide.settings:delete() -- always delete the config
event:Skip()
-- without explicit exit() the IDE crashes with SIGILL exception when closed
-- on MacOS compiled under 64bit with wxwidgets 2.9.3
if ide.osname == "Macintosh" then os.exit() end
end
frame:Connect(wx.wxEVT_CLOSE_WINDOW, CloseWindow)

View File

@@ -139,21 +139,15 @@ end
local function activateDocument(fileName, line)
if not fileName then return end
if not wx.wxIsAbsolutePath(fileName) then
fileName = wx.wxGetCwd().."/"..fileName
end
if wx.__WXMSW__ then
fileName = wx.wxUnix2DosFilename(fileName)
if not wx.wxIsAbsolutePath(fileName) and debugger.basedir then
fileName = debugger.basedir .. fileName
end
local activated
local fileName = wx.wxFileName(fileName)
for _, document in pairs(ide.openDocuments) do
local editor = document.editor
-- for running in cygwin, use same type of separators
local filePath = string.gsub(document.filePath, "\\", "/")
local fileName = string.gsub(fileName, "\\", "/")
if string.upper(filePath) == string.upper(fileName) then
if fileName:SameAs(wx.wxFileName(document.filePath)) then
local editor = document.editor
local selection = document.index
notebook:SetSelection(selection)
SetEditorSelection(selection)
@@ -196,8 +190,8 @@ debugger.shell = function(expression, isstatement)
-- exec command is not expected to return anything.
-- eval command returns 0 or more results.
-- 'values' has a list of serialized results returned.
-- as it is not possible to distinguish between 0 and nil returned,
-- 'nil' is always returned in this case.
-- as it is not possible to distinguish between 0 results and one
-- 'nil' value returned, 'nil' is always returned in this case.
-- the first value returned by eval command is not used;
-- this may need to be taken into account by other debuggers.
local addedret, forceexpression = true, expression:match("^%s*=%s*")
@@ -205,6 +199,7 @@ debugger.shell = function(expression, isstatement)
local _, values, err = debugger.evaluate(expression)
if not forceexpression and err and
(err:find("'<eof>' expected near '") or
err:find("'%(' expected near") or
err:find("unexpected symbol near '")) then
_, values, err = debugger.execute(expression)
addedret = false
@@ -214,12 +209,29 @@ debugger.shell = function(expression, isstatement)
if addedret then err = err:gsub('^%[string "return ', '[string "') end
DisplayShellErr(err)
elseif addedret or #values > 0 then
if forceexpression then -- display elements as multi-line
local mobdebug = require "mobdebug"
for i,v in pairs(values) do -- stringify each of the returned values
local func = loadstring('return '..v) -- deserialize the value first
if func then -- if it's deserialized correctly
values[i] = (forceexpression and i > 1 and '\n' or '') ..
mobdebug.line(func(), {nocode = true, comment = 0,
-- if '=' is used, then use multi-line serialized output
indent = forceexpression and ' ' or nil})
end
end
end
-- if empty table is returned, then show nil if this was an expression
if #values == 0 and (forceexpression or not isstatement) then
values = {'nil'}
end
DisplayShell((table.unpack or unpack)(values))
end
-- refresh Stack and Watch windows if executed a statement (and no err)
if isstatement and not err and not addret and #values == 0 then
updateStackSync() updateWatchesSync() end
end)
end
end
@@ -235,6 +247,11 @@ debugger.listen = function()
return
end
copas.setErrorHandler(function(error)
DisplayOutput("Can't start debugging session due to internal error '" .. error .. "'.\n")
debugger.terminate()
end)
local options = debugger.options or {}
if not debugger.scratchpad then SetAllEditorsReadOnly(true) end
local wxfilepath = GetEditorFileAndCurInfo()
@@ -248,6 +265,7 @@ debugger.listen = function()
debugger.socket = skt
debugger.loop = false
debugger.scratchable = false
debugger.stats = {line = 0}
-- load the remote file into the debugger
-- set basedir first, before loading to make sure that the path is correct
@@ -255,9 +273,15 @@ debugger.listen = function()
reSetBreakpoints()
if (options.run) then
local file, line = debugger.handle("run")
activateDocument(file, line)
if (options.startwith) then
local file, line, err = debugger.loadfile(options.startwith)
if err then
DisplayOutput(("Can't run the entry point script (%s). Compilation error:\n%s\n")
:format(options.startwith, err))
return debugger.terminate()
end
elseif (options.run) then
-- do nothing here
elseif (debugger.scratchpad) then
debugger.scratchpad.updated = true
else
@@ -267,27 +291,17 @@ debugger.listen = function()
-- with start() method, which can't load new files
-- if file and line are set, this indicates option #2
if file and line then
-- if the file name is absolute, try to load it
local activated
if wx.wxIsAbsolutePath(file) then
activated = activateDocument(file, line)
else
-- try to find a proper file based on file name
-- first check using basedir that was set based on current file path
if not activated then
activated = activateDocument(debugger.basedir..file, line)
end
local activated = activateDocument(file, line)
-- if not found, check using full file path and reset basedir
if not activated then
local path = wxfilepath:GetPath(wx.wxPATH_GET_VOLUME + wx.wxPATH_GET_SEPARATOR)
activated = activateDocument(path..file, line)
if activated then
debugger.basedir = path
debugger.handle("basedir " .. debugger.basedir)
-- reset breakpoints again as basedir has changed
reSetBreakpoints()
end
-- if not found, check using full file path and reset basedir
if not activated then
local path = wxfilepath:GetPath(wx.wxPATH_GET_VOLUME + wx.wxPATH_GET_SEPARATOR)
activated = activateDocument(path..file, line)
if activated then
debugger.basedir = path
debugger.handle("basedir " .. debugger.basedir)
-- reset breakpoints again as basedir has changed
reSetBreakpoints()
end
end
@@ -315,6 +329,16 @@ debugger.listen = function()
DisplayOutput(("Debugging session started in '%s'.\n")
:format(debugger.basedir))
if (options.runstart) then
ClearAllCurrentLineMarkers()
debugger.run()
end
if (options.run) then
local file, line = debugger.handle("run")
activateDocument(file, line)
end
end)
debugger.listening = true
end
@@ -349,10 +373,8 @@ debugger.exec = function(command)
DebuggerStop()
return
else
if debugger.basedir and not wx.wxIsAbsolutePath(file) then
file = debugger.basedir .. file
end
if activateDocument(file, line) then
debugger.stats.line = debugger.stats.line + 1
if debugger.loop then
updateStackSync()
updateWatchesSync()
@@ -361,7 +383,15 @@ debugger.exec = function(command)
return
end
else
out = "out" -- redo now trying to get out of this file
-- redo now; if the call is from the debugger, then repeat
-- the same command, except when it was "run" (switch to 'step');
-- this is needed to "break" execution that happens in on() call.
-- in all other cases get out of this file.
-- don't get out of "mobdebug", because it may happen with
-- start() or on() call, which will get us out of the current
-- file, which is not what we want.
out = (file:find('mobdebug%.lua$')
and (command == 'run' and 'step' or command) or "out")
end
end
end
@@ -427,6 +457,17 @@ end
debugger.breakpoint = function(file, line, state)
debugger.handleAsync((state and "setb " or "delb ") .. file .. " " .. line)
end
debugger.quickeval = function(var, callback)
if debugger.server and not debugger.running then
copas.addthread(function ()
local _, values, err = debugger.evaluate(var)
local val = err
and err:gsub("%[.-%]:%d+:%s*","error: ")
or (var .. " = " .. (#values > 0 and values[1] or 'nil'))
if callback then callback(val) end
end)
end
end
----------------------------------------------
-- public api
@@ -450,7 +491,13 @@ function DebuggerStop()
ShellSupportRemote(nil)
ClearAllCurrentLineMarkers()
DebuggerScratchpadOff()
DisplayOutput("Debugging session completed.\n")
DisplayOutput(("Debugging session completed (traced %d instruction%s).\n")
:format(debugger.stats.line, debugger.stats.line == 1 and '' or 's'))
else
-- it's possible that the application couldn't start, or that the
-- debugger in the application didn't start, which means there is
-- no debugger.server, but scratchpad may still be on. Turn it off.
DebuggerScratchpadOff()
end
end
@@ -474,17 +521,18 @@ end
-- of it and if done inside a function, icons do not work as expected
local imglist = wx.wxImageList(16,16)
do
local getBitmap = (ide.app.createbitmap or wx.wxArtProvider.GetBitmap)
local size = wx.wxSize(16,16)
-- 0 = stack call
imglist:Add((ide.app.createbitmap or wx.wxArtProvider.GetBitmap)(wx.wxART_GO_FORWARD, wx.wxART_OTHER, size))
imglist:Add(getBitmap(wx.wxART_GO_FORWARD, wx.wxART_OTHER, size))
-- 1 = local variables
imglist:Add((ide.app.createbitmap or wx.wxArtProvider.GetBitmap)(wx.wxART_LIST_VIEW, wx.wxART_OTHER, size))
imglist:Add(getBitmap(wx.wxART_LIST_VIEW, wx.wxART_OTHER, size))
-- 2 = upvalues
imglist:Add((ide.app.createbitmap or wx.wxArtProvider.GetBitmap)(wx.wxART_REPORT_VIEW, wx.wxART_OTHER, size))
imglist:Add(getBitmap(wx.wxART_REPORT_VIEW, wx.wxART_OTHER, size))
end
function DebuggerCreateStackWindow()
if (debugger.stackWindow) then return end
if (debugger.stackWindow) then return updateStackAndWatches() end
local width = 360
local stackWindow = wx.wxFrame(ide.frame, wx.wxID_ANY,
"Stack Window",
@@ -542,7 +590,7 @@ function DebuggerCreateStackWindow()
end
function DebuggerCreateWatchWindow()
if (debugger.watchWindow) then return end
if (debugger.watchWindow) then return updateWatches() end
local width = 360
local watchWindow = wx.wxFrame(ide.frame, wx.wxID_ANY,
"Watch Window",
@@ -651,10 +699,7 @@ function DebuggerCreateWatchWindow()
end
function DebuggerMakeFileName(editor, filePath)
if not filePath then
filePath = "file"..tostring(editor)
end
return filePath
return filePath or ide.config.default.fullname
end
function DebuggerToggleBreakpoint(editor, line)
@@ -684,7 +729,7 @@ function DebuggerRefreshScratchpad()
if debugger.scratchpad.running then
-- break the current execution first
-- don't try too frequently to avoid overwhelming the debugger
local now = os.clock()
local now = TimeGet()
if now - debugger.scratchpad.running > 0.250 then
debugger.breaknow()
debugger.scratchpad.running = now
@@ -692,21 +737,37 @@ function DebuggerRefreshScratchpad()
else
local clear = ide.frame.menuBar:IsChecked(ID_CLEAROUTPUT)
local scratchpadEditor = debugger.scratchpad.editor
local code = scratchpadEditor:GetText()
-- take editor text and remove shebang line
local code = scratchpadEditor:GetText():gsub("^#!.-\n", "\n")
local filePath = DebuggerMakeFileName(scratchpadEditor,
ide.openDocuments[scratchpadEditor:GetId()].filePath)
-- this is a special error message that is generated at the very end
-- of each script to avoid exiting the (debugee) scratchpad process.
-- these errors are handled and not reported to the user
local errormsg = 'execution suspended at ' .. os.clock()
local errormsg = 'execution suspended at ' .. TimeGet()
local stopper = "\ndo error('" .. errormsg .. "') end"
-- store if interpreter requires a special handling for external loop
local extloop = ide.interpreter.scratchextloop
local function reloadScratchpadCode()
debugger.scratchpad.running = os.clock()
debugger.scratchpad.running = TimeGet()
debugger.scratchpad.updated = false
debugger.scratchpad.runs = (debugger.scratchpad.runs or 0) + 1
-- the code can be running in two ways under scratchpad:
-- 1. controlled by the application, requires stopper (most apps)
-- 2. controlled by some external loop (for example, love2d).
-- in the first case we need to reload the app after each change
-- in the second case, we need to load the app once and then
-- "execute" new code to reflect the changes (with some limitations).
local _, _, err
if extloop then -- if the execution is controlled by an external loop
if debugger.scratchpad.runs == 1
then _, _, err = debugger.loadstring(filePath, code)
else _, _, err = debugger.execute(code) end
else _, _, err = debugger.loadstring(filePath, code .. stopper) end
local _, _, err = debugger.loadstring(filePath, code .. stopper)
local prefix = "Compilation error"
if clear then ClearOutput() end

View File

@@ -18,7 +18,7 @@ local projcombobox = ide.frame.projpanel.projcombobox
local statusTextTable = { "OVR?", "R/O?", "Cursor Pos" }
-- set funclist font to be the same as the combobox in the project dropdown
funclist:SetFont(projcombobox:GetFont())
funclist:SetFont(ide.font.fNormal)
local function updateStatusText(editor)
local texts = { "", "", "" }
@@ -27,9 +27,10 @@ local function updateStatusText(editor)
local line = editor:LineFromPosition(pos)
local col = 1 + pos - editor:PositionFromLine(line)
texts = { iff(editor:GetOvertype(), "OVR", "INS"),
texts = {
iff(editor:GetOvertype(), "OVR", "INS"),
iff(editor:GetReadOnly(), "R/O", "R/W"),
"Ln "..tostring(line + 1).." Col "..tostring(col) }
"Ln: "..tostring(line + 1).." Col: "..tostring(col) }
end
if ide.frame then
@@ -139,8 +140,6 @@ function SetEditorSelection(selection)
statusBar:SetStatusText("",1)
ide.frame:SetTitle(getFileTitle(editor))
FileTreeMarkSelected('')
if editor then
if funclist:IsEmpty() then funclist:Append('Jump to a function definition...', 0) end
funclist:SetSelection(0)
@@ -151,6 +150,8 @@ function SetEditorSelection(selection)
if openDocuments[id] and openDocuments[id].filePath then
FileTreeMarkSelected(openDocuments[id].filePath)
end
else
FileTreeMarkSelected('')
end
end
@@ -181,7 +182,7 @@ end
-- Set if the document is modified and update the notebook page text
function SetDocumentModified(id, modified)
local pageText = openDocuments[id].fileName or "untitled.lua"
local pageText = openDocuments[id].fileName or ide.config.default.fullname
if modified then
pageText = "* "..pageText
@@ -191,6 +192,83 @@ function SetDocumentModified(id, modified)
notebook:SetPageText(openDocuments[id].index, pageText)
end
function EditorAutoComplete(editor)
if (editor == nil or not editor.spec) then return end
-- retrieve the current line and get a string to the current cursor position in the line
local pos = editor:GetCurrentPos()
local line = editor:GetCurrentLine()
local linetx = editor:GetLine(line)
local linestart = editor:PositionFromLine(line)
local localpos = pos-linestart
local lt = linetx:sub(1,localpos)
lt = lt:gsub("%s*("..editor.spec.sep..")%s*",function(a) return a end)
lt = lt:gsub("%s*%b[]%s*","")
lt = lt:gsub("%s*%b()%s*","")
lt = lt:gsub("%s*%b{}%s*","")
lt = lt:match("[^%[%(%s]*$")
lt = lt:gsub("%s","")
-- know now which string is to be completed
local userList = CreateAutoCompList(editor,lt)
if userList and string.len(userList) > 0 then
editor:UserListShow(1, userList)
elseif editor:AutoCompActive() then
editor:AutoCompCancel()
end
end
function EditorCallTip(editor, pos)
local line = editor:LineFromPosition(pos)
local linetx = editor:GetLine(line)
local linestart = editor:PositionFromLine(line)
local localpos = pos-linestart
local ident = "([a-zA-Z_0-9][a-zA-Z_0-9%.%:]*)"
local linetxtopos = linetx:sub(1,localpos)
linetxtopos = linetxtopos..")"
linetxtopos = linetxtopos:match(ident .. "%b()$")
local tip = linetxtopos and GetTipInfo(editor,linetxtopos.."(",false)
if ide.debugger and ide.debugger.server then
local selected = editor:GetSelectionStart() ~= editor:GetSelectionEnd()
and pos >= editor:GetSelectionStart() and pos <= editor:GetSelectionEnd()
-- check if we have a selected text or an identifier
-- for an identifier, check fragments on the left and on the right.
-- this is to match 'io' in 'i^o.print' and 'io.print' in 'io.pr^int'.
-- remove square brackets to make tbl[index].x show proper values.
local start = linetx:sub(1,localpos)
:gsub("%b[]", function(s) return ("."):rep(#s) end)
:find(ident.."$")
-- check if the style is the right one; this is to ignore
-- comments, strings, numbers (to avoid '1 = 1'), keywords, and such
if start and not selected then
local style = bit.band(editor:GetStyleAt(linestart+start),31)
if editor.spec.iscomment[style]
or editor.spec.isstring[style]
or style == wxstc.wxSTC_LUA_NUMBER
or style == wxstc.wxSTC_LUA_WORD then
return -- don't do anything for strings or comments or numbers
end
end
local right = linetx:sub(localpos+1,#linetx):match("^[a-zA-Z_0-9]*")
local var = selected and editor:GetSelectedText()
or (start and linetx:sub(start,localpos):gsub(":",".")..right or nil)
if var then
local limit = 128
ide.debugger.quickeval(var, function(val)
if #val > limit then val = val:sub(1, limit-3).."..." end
editor:CallTipShow(pos, val) end)
end
elseif tip then
editor:CallTipShow(pos, tip)
end
end
-- ----------------------------------------------------------------------------
-- Create an editor and add it to the notebook
function CreateEditor(name)
@@ -206,8 +284,8 @@ function CreateEditor(name)
editor:SetBufferedDraw(true)
editor:StyleClearAll()
editor:SetFont(ide.font)
editor:StyleSetFont(wxstc.wxSTC_STYLE_DEFAULT, ide.font)
editor:SetFont(ide.font.eNormal)
editor:StyleSetFont(wxstc.wxSTC_STYLE_DEFAULT, ide.font.eNormal)
editor:SetTabWidth(ide.config.editor.tabwidth or 4)
editor:SetIndent(ide.config.editor.tabwidth or 4)
@@ -258,6 +336,10 @@ function CreateEditor(name)
editor:MarkerDefine(wxstc.wxSTC_MARKNUM_FOLDERMIDTAIL, wxstc.wxSTC_MARK_TCORNER, wx.wxWHITE, grey)
grey:delete()
if ide.config.editor.calltipdelay and ide.config.editor.calltipdelay > 0 then
editor:SetMouseDwellTime(ide.config.editor.calltipdelay)
end
editor:AutoCompSetIgnoreCase(ide.config.acandtip.ignorecase)
if (ide.config.acandtip.strategy > 0) then
editor:AutoCompSetAutoHide(0)
@@ -334,26 +416,37 @@ function CreateEditor(name)
editor:GotoPos(pos+indent)
end
end
elseif ch == ("("):byte() then
elseif ch == ("("):byte() then
local tip = GetTipInfo(editor,linetxtopos,ide.config.acandtip.shorttip)
if tip then
editor:CallTipShow(pos,tip)
end
elseif ide.config.autocomplete then -- code completion prompt
local trigger = linetxtopos:match("["..editor.spec.sep.."%w_]+$")
if (trigger and (#trigger > 1 or trigger:match("[%.:]"))) then
-- defined in menu_edit.lua
local commandEvent = wx.wxCommandEvent(wx.wxEVT_COMMAND_MENU_SELECTED,
ID_AUTOCOMPLETE)
wx.wxPostEvent(ide.frame, commandEvent)
ide.frame:AddPendingEvent(wx.wxCommandEvent(
wx.wxEVT_COMMAND_MENU_SELECTED, ID_AUTOCOMPLETE))
end
end
end)
editor:Connect(wxstc.wxEVT_STC_DWELLSTART,
function (event)
local position = editor:PositionFromPointClose(event:GetX(),event:GetY())
if position ~= wxstc.wxSTC_INVALID_POSITION then
EditorCallTip(editor, position)
end
event:Skip()
end)
editor:Connect(wxstc.wxEVT_STC_DWELLEND,
function (event)
if editor:CallTipActive() then editor:CallTipCancel() end
event:Skip()
end)
editor:Connect(wxstc.wxEVT_STC_USERLISTSELECTION,
function (event)
local pos = editor:GetCurrentPos()
@@ -363,17 +456,17 @@ function CreateEditor(name)
end)
editor:Connect(wxstc.wxEVT_STC_SAVEPOINTREACHED,
function (event)
function ()
SetDocumentModified(editor:GetId(), false)
end)
editor:Connect(wxstc.wxEVT_STC_SAVEPOINTLEFT,
function (event)
function ()
SetDocumentModified(editor:GetId(), true)
end)
editor:Connect(wxstc.wxEVT_STC_UPDATEUI,
function (event)
function ()
updateStatusText(editor)
updateBraceMatch(editor)
for _,iv in ipairs(editor.ev) do
@@ -389,7 +482,7 @@ function CreateEditor(name)
function (event)
if MarkupHotspotClick then
local position = editor:PositionFromPointClose(event:GetX(),event:GetY())
if position ~= wx.wxSTC_INVALID_POSITION then
if position ~= wxstc.wxSTC_INVALID_POSITION then
if MarkupHotspotClick(position, editor) then return end
end
end
@@ -423,6 +516,9 @@ function CreateEditor(name)
then notebook:SetSelection(first)
else notebook:AdvanceSelection(true) end
else
if ide.osname == 'Macintosh' and event:CmdDown() then
return -- ignore a key press if Command key is also pressed
end
event:Skip()
end
end)
@@ -448,10 +544,10 @@ function GetSpec(ext,forcespec)
-- search proper spec
-- allow forcespec for "override"
if ext and not spec then
for i,curspec in pairs(ide.specs) do
for _,curspec in pairs(ide.specs) do
local exts = curspec.exts
if (exts) then
for n,curext in ipairs(exts) do
for _,curext in ipairs(exts) do
if (curext == ext) then
spec = curspec
break
@@ -475,16 +571,11 @@ function IndicateFunctions(editor, lines, linee)
if (lines < 0) then return end
local isfunc = editor.spec.isfncall
local iscomment = editor.spec.iscomment
local iskeyword0 = editor.spec.iskeyword0
local isfncall = editor.spec.isfncall
local isinvalid = {}
for i,v in pairs(iscomment) do
isinvalid[i] = v
end
for i,v in pairs(iskeyword0) do
isinvalid[i] = v
end
for i,v in pairs(editor.spec.iscomment) do isinvalid[i] = v end
for i,v in pairs(editor.spec.iskeyword0) do isinvalid[i] = v end
for i,v in pairs(editor.spec.isstring) do isinvalid[i] = v end
local INDICS_MASK = wxstc.wxSTC_INDICS_MASK
local INDIC0_MASK = wxstc.wxSTC_INDIC0_MASK
@@ -501,13 +592,13 @@ function IndicateFunctions(editor, lines, linee)
while from do
tx = from==1 and tx or string.sub(tx,from)
local f,t,w = isfunc(tx)
local f,t,w = isfncall(tx)
if (f) then
local p = ls+f+off
local s = bit.band(editor:GetStyleAt(p),31)
editor:StartStyling(p,INDICS_MASK)
editor:SetStyling(t-f,isinvalid[s] and 0 or (INDIC0_MASK + 1))
editor:SetStyling(#w,isinvalid[s] and 0 or (INDIC0_MASK + 1))
off = off + t
end
from = t and (t+1)
@@ -534,11 +625,11 @@ function SetupKeywords(editor, ext, forcespec, styles, font, fontitalic)
-- Get the items in the global "wx" table for autocompletion
if not wxkeywords then
local keyword_table = {}
for index, value in pairs(wx) do
for index in pairs(wx) do
table.insert(keyword_table, "wx."..index.." ")
end
for index, value in pairs(wxstc) do
for index in pairs(wxstc) do
table.insert(keyword_table, "wxstc."..index.." ")
end
@@ -560,7 +651,7 @@ function SetupKeywords(editor, ext, forcespec, styles, font, fontitalic)
end
StylesApplyToEditor(styles or ide.config.styles, editor,
font or ide.font,fontitalic or ide.fontItalic,lexerstyleconvert)
font or ide.font.eNormal,fontitalic or ide.font.eItalic,lexerstyleconvert)
end
----------------------------------------------------
@@ -588,9 +679,13 @@ funclist:Connect(wx.wxEVT_SET_FOCUS,
local linee = editor:GetLineCount()-1
for line=lines,linee do
local tx = editor:GetLine(line)
local s,e,cap,l = editor.spec.isfndef(tx)
local s,_,cap,l = editor.spec.isfndef(tx)
if (s) then
funclist:Append((l and " " or "")..cap,line)
local ls = editor:PositionFromLine(line)
local style = bit.band(editor:GetStyleAt(ls+s),31)
if not (editor.spec.iscomment[style] or editor.spec.isstring[style]) then
funclist:Append((l and " " or "")..cap,line)
end
end
end

View File

@@ -30,14 +30,15 @@ local filetree = ide.filetree
-- ------------
do
local getBitmap = (ide.app.createbitmap or wx.wxArtProvider.GetBitmap)
local size = wx.wxSize(16, 16)
filetree.imglist = wx.wxImageList(16,16)
-- 0 = directory
filetree.imglist:Add(wx.wxArtProvider.GetBitmap(wx.wxART_FOLDER, wx.wxART_OTHER, size))
filetree.imglist:Add(getBitmap(wx.wxART_FOLDER, wx.wxART_OTHER, size))
-- 1 = file known spec
filetree.imglist:Add(wx.wxArtProvider.GetBitmap(wx.wxART_HELP_PAGE, wx.wxART_OTHER, size))
filetree.imglist:Add(getBitmap(wx.wxART_HELP_PAGE, wx.wxART_OTHER, size))
-- 2 = file rest
filetree.imglist:Add(wx.wxArtProvider.GetBitmap(wx.wxART_NORMAL_FILE, wx.wxART_OTHER, size))
filetree.imglist:Add(getBitmap(wx.wxART_NORMAL_FILE, wx.wxART_OTHER, size))
end
local function treeAddDir(tree,parent_id,rootdir)
@@ -46,15 +47,14 @@ local function treeAddDir(tree,parent_id,rootdir)
while true do
if not item:IsOk() then break end
items[tree:GetItemText(item) .. tree:GetItemImage(item)] = item
item, cookie = tree:GetNextChild(item, cookie)
item, cookie = tree:GetNextChild(parent_id, cookie)
end
local curr
local search = rootdir..string_Pathsep.."*.*"
local dirs = FileSysGet(search,wx.wxDIR)
local search = rootdir..string_Pathsep.."*"
-- append directories
for _,dir in ipairs(dirs) do
for _,dir in ipairs(FileSysGet(search,wx.wxDIR)) do
local name = dir:match("%"..string_Pathsep.."("..stringset_File.."+)$")
local icon = 0
local item = items[name .. icon]
@@ -78,8 +78,7 @@ local function treeAddDir(tree,parent_id,rootdir)
end
-- then append files
local files = FileSysGet(search,wx.wxFILE)
for _,file in ipairs(files) do
for _,file in ipairs(FileSysGet(search,wx.wxFILE)) do
local name = file:match("%"..string_Pathsep.."("..stringset_File.."+)$")
local known = GetSpec(GetFileExt(name))
local icon = known and 1 or 2
@@ -122,15 +121,17 @@ local function treeGetItemFullName(tree,treedata,item_id)
cur = tree:GetItemText(item_id)
if cur and string.len(cur) > 0 then str = cur..string_Pathsep..str end
end
return ((not filetree.showroot) and filetree.projdata.rootdir or "")..str
-- as root may already include path separate, normalize the path
local fullPath = wx.wxFileName(
filetree.showroot and str or filetree.projdata.rootdir .. str)
fullPath:Normalize()
return fullPath:GetFullPath()
end
local function treeSetRoot(tree,treedata,rootdir)
tree:DeleteAllItems()
if (not wx.wxDirExists(rootdir)) then
treedata.root_id = nil
tree:AddRoot("Invalid")
return
end
@@ -172,7 +173,6 @@ local function treeSetConnectorsAndIcons(tree,treedata)
else -- open file
if wx.wxFileName(name):FileExists() then
LoadFile(name,nil,true)
FileTreeMarkSelected(name)
else -- stale filetree information; rescan
treeAddDir(tree,tree:GetItemParent(item_id),name)
end
@@ -199,7 +199,8 @@ local projtree = wx.wxTreeCtrl(projpanel, ID "filetree.projtree",
or (wx.wxTR_HAS_BUTTONS + wx.wxTR_SINGLE + wx.wxTR_HIDE_ROOT))
-- use the same font in the combobox as is used in the filetree
projcombobox:SetFont(projtree:GetFont())
projtree:SetFont(ide.font.fNormal)
projcombobox:SetFont(ide.font.fNormal)
local projTopSizer = wx.wxBoxSizer( wx.wxHORIZONTAL );
projTopSizer:Add(projcombobox, 1, wx.wxALL + wx.wxALIGN_LEFT + wx.wxGROW, 0)
@@ -284,7 +285,7 @@ local function findItem(tree, match)
local node = projtree:GetRootItem()
local label = tree:GetItemText(node)
local s, e = string.find(match, label)
local s, e = string.find(match, label, 1, true)
if not s or s ~= 1 then return end
for token in string.gmatch(string.sub(match,e+1), "[^%"..string_Pathsep.."]+") do
@@ -298,7 +299,7 @@ local function findItem(tree, match)
node = item
break
end
item, cookie = tree:GetNextChild(item, cookie)
item, cookie = tree:GetNextChild(node, cookie)
end
end
@@ -306,18 +307,32 @@ local function findItem(tree, match)
return node
end
local curr_id
local curr_file
function FileTreeMarkSelected(file)
if not file then return end
if not file or not filetree.projdirText or #filetree.projdirText == 0 then return end
local item_id = findItem(projtree, file)
if curr_id ~= item_id then
if curr_id and projtree:IsBold(curr_id) then
projtree:SetItemBold(curr_id, false)
-- if the select item is different from the current one
-- or the current one is the same, but not bold (which may happen when
-- the project is changed to one that includes the current item)
if curr_file ~= file
or item_id and not projtree:IsBold(item_id) then
if curr_file then
local curr_id = findItem(projtree, curr_file)
if curr_id and projtree:IsBold(curr_id) then
projtree:SetItemBold(curr_id, false)
end
end
if item_id then
projtree:EnsureVisible(item_id)
projtree:SetItemBold(item_id, true)
curr_id = item_id
end
curr_file = file
projtree:Refresh() -- to force refresh on Mac (ide.osname == 'Macintosh')
end
end
function FileTreeRefresh()
treeSetRoot(projtree,filetree.projdata,filetree.projdirText)
end

View File

@@ -112,7 +112,7 @@ function findReplace:FindString(reverse)
end
if posFind == -1 then
findReplace.foundString = false
ide.frame:SetStatusText("Find text not found.")
ide.frame:SetStatusText("Text not found.")
else
findReplace.foundString = true
local start = editor:GetTargetStart()
@@ -209,48 +209,36 @@ local function onFileRegister(pos)
findReplace.occurrences = findReplace.occurrences + 1
end
local function storefile(file,content)
local handle = io.open(file, "wb")
if (handle) then
handle:write(content)
handle:close()
end
end
local function ProcInFiles(startdir,mask,subdirs,replace)
if (subdirs) then
local dirs = FileSysGet(startdir..string_Pathsep.."*.*",wx.wxDIR)
for i,dir in ipairs(dirs) do
--DisplayOutput(dir.."\n")
local dirs = FileSysGet(startdir..string_Pathsep.."*",wx.wxDIR)
for _,dir in ipairs(dirs) do
ProcInFiles(dir,mask,true,replace)
end
end
local files = FileSysGet(startdir..string_Pathsep..mask,wx.wxFILE)
for i,file in ipairs(files) do
findReplace.curfilename = file
for _,file in ipairs(files) do
-- ignore .bak files when replacing and asked to store .bak files
if not (replace and findReplace.fMakeBak and file:find('.bak$')) then
findReplace.curfilename = file
--DisplayOutput(file.."\n")
local filetext = FileRead(file)
if filetext then
findReplace.oveditor:SetText(filetext)
-- load file
local handle = io.open(file, "rb")
if handle then
local filetext = handle:read("*a")
handle:close()
findReplace.oveditor:SetText(filetext)
if (replace and findReplace:ReplaceString(true,onFileRegister)) then
-- store changed content, make .bak
if (findReplace.fMakeBak) then
storefile(file..".bak",filetext)
if replace then
-- check if anything replaced, store changed content, make .bak
if findReplace:ReplaceString(true,onFileRegister)
and findReplace.fMakeBak and FileWrite(file..".bak",filetext) then
FileWrite(file,findReplace.oveditor:GetText())
end
else
findReplace:FindStringAll(onFileRegister)
end
storefile(file,findReplace.oveditor:GetText())
else
findReplace:FindStringAll(onFileRegister)
end
end
end
end
function findReplace:RunInFiles(replace)
@@ -265,11 +253,12 @@ function findReplace:RunInFiles(replace)
local fname = wx.wxFileName(findReplace.filedirText)
local startdir = findReplace.filedirText
DisplayOutput("> FindInFiles "..(replace and "Replacing" or "Searching")..": '"..findReplace.findText.."'\n")
DisplayOutput("FindInFiles: "..(replace and "Replacing" or "Searching for").." '"..findReplace.findText.."'.\n")
ProcInFiles(startdir, findReplace.filemaskText,findReplace.fSubDirs, replace)
ProcInFiles(startdir, findReplace.filemaskText, findReplace.fSubDirs, replace)
DisplayOutput("> FindInFiles: "..findReplace.occurrences.." occurrence(s) have been found\n\n")
DisplayOutput("FindInFiles: "..findReplace.occurrences.." instance(s) have been "..
(replace and "replaced" or "found")..".\n")
findReplace.oveditor = nil
end
@@ -440,7 +429,7 @@ local function createFindReplaceDialog(replace,infiles)
end
findDialog:Connect(ID_FIND_NEXT, wx.wxEVT_COMMAND_BUTTON_CLICKED,
function(event)
function()
TransferDataFromWindow()
if (findReplace.infiles) then
findReplace:RunInFiles()
@@ -479,8 +468,8 @@ local function createFindReplaceDialog(replace,infiles)
if infilesDirButton then
findDialog:Connect(ID_SETDIR, wx.wxEVT_COMMAND_BUTTON_CLICKED,
function(event)
local filePicker = wx.wxDirDialog(findDialog, "Chose a project directory",
function()
local filePicker = wx.wxDirDialog(findDialog, "Choose a project directory",
findReplace.filedirText~="" and findReplace.filedirText or wx.wxGetCwd(),wx.wxFLP_USE_TEXTCTRL)
local res = filePicker:ShowModal(true)

View File

@@ -10,41 +10,23 @@ BREAKPOINT_MARKER_VALUE = 2 -- = 2^BREAKPOINT_MARKER
CURRENT_LINE_MARKER = 2
CURRENT_LINE_MARKER_VALUE = 4 -- = 2^CURRENT_LINE_MARKER
-- Globals
local font = nil -- fonts to use for the editor
local fontItalic = nil
local ofont = nil -- fonts to use for the outputshell
local ofontItalic = nil
-- ----------------------------------------------------------------------------
-- Pick some reasonable fixed width fonts to use for the editor
if wx.__WXMSW__ then
font = wx.wxFont(ide.config.editor.fontsize or 10, wx.wxFONTFAMILY_MODERN, wx.wxFONTSTYLE_NORMAL,
wx.wxFONTWEIGHT_NORMAL, false, ide.config.editor.fontname or "Courier New", ide.config.editor.fontencoding or wx.wxFONTENCODING_DEFAULT)
fontItalic = wx.wxFont(ide.config.editor.fontsize or 10, wx.wxFONTFAMILY_MODERN, wx.wxFONTSTYLE_ITALIC,
wx.wxFONTWEIGHT_NORMAL, false, ide.config.editor.fontname or "Courier New", ide.config.editor.fontencoding or wx.wxFONTENCODING_DEFAULT)
else
font = wx.wxFont(ide.config.editor.fontsize or 10, wx.wxFONTFAMILY_MODERN, wx.wxFONTSTYLE_NORMAL,
wx.wxFONTWEIGHT_NORMAL, false, ide.config.editor.fontname or "", ide.config.editor.fontencoding or wx.wxFONTENCODING_DEFAULT)
fontItalic = wx.wxFont(ide.config.editor.fontsize or 10, wx.wxFONTFAMILY_MODERN, wx.wxFONTSTYLE_ITALIC,
wx.wxFONTWEIGHT_NORMAL, false, ide.config.editor.fontname or "", ide.config.editor.fontencoding or wx.wxFONTENCODING_DEFAULT)
local function setFont(style, config, name, size)
return wx.wxFont(config.fontsize or size or 10, wx.wxFONTFAMILY_MODERN, style,
wx.wxFONTWEIGHT_NORMAL, false, config.fontname or name,
config.fontencoding or wx.wxFONTENCODING_DEFAULT)
end
ide.font.eNormal = setFont(wx.wxFONTSTYLE_NORMAL, ide.config.editor, wx.__WXMSW__ and "Courier New" or "")
ide.font.eItalic = setFont(wx.wxFONTSTYLE_ITALIC, ide.config.editor, wx.__WXMSW__ and "Courier New" or "")
if wx.__WXMSW__ then
ofont = wx.wxFont(ide.config.outputshell.fontsize or 10, wx.wxFONTFAMILY_MODERN, wx.wxFONTSTYLE_NORMAL,
wx.wxFONTWEIGHT_NORMAL, false, ide.config.outputshell.fontname or "Courier New", ide.config.outputshell.fontencoding or wx.wxFONTENCODING_DEFAULT)
ofontItalic = wx.wxFont(ide.config.outputshell.fontsize or 10, wx.wxFONTFAMILY_MODERN, wx.wxFONTSTYLE_ITALIC,
wx.wxFONTWEIGHT_NORMAL, false, ide.config.outputshell.fontname or "Courier New", ide.config.outputshell.fontencoding or wx.wxFONTENCODING_DEFAULT)
else
ofont = wx.wxFont(ide.config.outputshell.fontsize or 10, wx.wxFONTFAMILY_MODERN, wx.wxFONTSTYLE_NORMAL,
wx.wxFONTWEIGHT_NORMAL, false, ide.config.outputshell.fontname or "", ide.config.outputshell.fontencoding or wx.wxFONTENCODING_DEFAULT)
ofontItalic = wx.wxFont(ide.config.outputshell.fontsize or 10, wx.wxFONTFAMILY_MODERN, wx.wxFONTSTYLE_ITALIC,
wx.wxFONTWEIGHT_NORMAL, false, ide.config.outputshell.fontname or "", ide.config.outputshell.fontencoding or wx.wxFONTENCODING_DEFAULT)
end
ide.font.oNormal = setFont(wx.wxFONTSTYLE_NORMAL, ide.config.outputshell, wx.__WXMSW__ and "Courier New" or "")
ide.font.oItalic = setFont(wx.wxFONTSTYLE_ITALIC, ide.config.outputshell, wx.__WXMSW__ and "Courier New" or "")
ide.font = font
ide.fontItalic = fontItalic
ide.ofont = ofont
ide.ofontItalic = ofontItalic
-- treeCtrl font requires slightly different handling
local gui, config = wx.wxTreeCtrl():GetFont(), ide.config.filetree
if config.fontsize then gui:SetPointSize(config.fontsize) end
if config.fontname then gui:SetFaceName(config.fontname) end
ide.font.fNormal = gui
-- ----------------------------------------------------------------------------
-- Create the wxFrame
@@ -65,18 +47,21 @@ local function createFrame()
end)
local menuBar = wx.wxMenuBar()
frame.menuBar = menuBar
local statusBar = frame:CreateStatusBar( 5 )
frame.statusBar = statusBar
local status_txt_width = statusBar:GetTextExtent("OVRW")
statusBar:SetStatusWidths({-1, status_txt_width*6, status_txt_width, status_txt_width, status_txt_width*5})
local statusBar = frame:CreateStatusBar(6)
local section_width = statusBar:GetTextExtent("OVRW")
statusBar:SetStatusStyles({wx.wxSB_RAISED, wx.wxSB_RAISED, wx.wxSB_RAISED,
wx.wxSB_RAISED, wx.wxSB_RAISED, wx.wxSB_RAISED})
statusBar:SetStatusWidths(
{-1, section_width*6, section_width, section_width, section_width*4, section_width*4})
statusBar:SetStatusText(GetIDEString("statuswelcome"))
local mgr = wxaui.wxAuiManager()
frame.uimgr = mgr
mgr:SetManagedWindow(frame)
frame.menuBar = menuBar
frame.statusBar = statusBar
frame.uimgr = mgr
return frame
end
@@ -86,23 +71,24 @@ local function createToolBar(frame)
local funclist = wx.wxChoice.new(toolBar,ID "toolBar.funclist",wx.wxDefaultPosition, wx.wxSize.new(240,16))
-- note: Ususally the bmp size isn't necessary, but the HELP icon is not the right size in MSW
local getBitmap = (ide.app.createbitmap or wx.wxArtProvider.GetBitmap)
local toolBmpSize = toolBar:GetToolBitmapSize()
toolBar:AddTool(ID_NEW, "New", wx.wxArtProvider.GetBitmap(wx.wxART_NORMAL_FILE, wx.wxART_TOOLBAR, toolBmpSize), "Create an empty document")
toolBar:AddTool(ID_OPEN, "Open", wx.wxArtProvider.GetBitmap(wx.wxART_FILE_OPEN, wx.wxART_TOOLBAR, toolBmpSize), "Open an existing document")
toolBar:AddTool(ID_SAVE, "Save", wx.wxArtProvider.GetBitmap(wx.wxART_FILE_SAVE, wx.wxART_TOOLBAR, toolBmpSize), "Save the current document")
toolBar:AddTool(ID_SAVEALL, "Save All", wx.wxArtProvider.GetBitmap(wx.wxART_NEW_DIR, wx.wxART_TOOLBAR, toolBmpSize), "Save all documents")
toolBar:AddTool(ID_NEW, "New", getBitmap(wx.wxART_NORMAL_FILE, wx.wxART_TOOLBAR, toolBmpSize), "Create an empty document")
toolBar:AddTool(ID_OPEN, "Open", getBitmap(wx.wxART_FILE_OPEN, wx.wxART_TOOLBAR, toolBmpSize), "Open an existing document")
toolBar:AddTool(ID_SAVE, "Save", getBitmap(wx.wxART_FILE_SAVE, wx.wxART_TOOLBAR, toolBmpSize), "Save the current document")
toolBar:AddTool(ID_SAVEALL, "Save All", getBitmap(wx.wxART_NEW_DIR, wx.wxART_TOOLBAR, toolBmpSize), "Save all documents")
toolBar:AddSeparator()
toolBar:AddTool(ID_CUT, "Cut", wx.wxArtProvider.GetBitmap(wx.wxART_CUT, wx.wxART_TOOLBAR, toolBmpSize), "Cut the selection")
toolBar:AddTool(ID_COPY, "Copy", wx.wxArtProvider.GetBitmap(wx.wxART_COPY, wx.wxART_TOOLBAR, toolBmpSize), "Copy the selection")
toolBar:AddTool(ID_PASTE, "Paste", wx.wxArtProvider.GetBitmap(wx.wxART_PASTE, wx.wxART_TOOLBAR, toolBmpSize), "Paste text from the clipboard")
toolBar:AddTool(ID_CUT, "Cut", getBitmap(wx.wxART_CUT, wx.wxART_TOOLBAR, toolBmpSize), "Cut the selection")
toolBar:AddTool(ID_COPY, "Copy", getBitmap(wx.wxART_COPY, wx.wxART_TOOLBAR, toolBmpSize), "Copy the selection")
toolBar:AddTool(ID_PASTE, "Paste", getBitmap(wx.wxART_PASTE, wx.wxART_TOOLBAR, toolBmpSize), "Paste text from the clipboard")
toolBar:AddSeparator()
toolBar:AddTool(ID_UNDO, "Undo", wx.wxArtProvider.GetBitmap(wx.wxART_UNDO, wx.wxART_TOOLBAR, toolBmpSize), "Undo last edit")
toolBar:AddTool(ID_REDO, "Redo", wx.wxArtProvider.GetBitmap(wx.wxART_REDO, wx.wxART_TOOLBAR, toolBmpSize), "Redo last undo")
toolBar:AddTool(ID_UNDO, "Undo", getBitmap(wx.wxART_UNDO, wx.wxART_TOOLBAR, toolBmpSize), "Undo last edit")
toolBar:AddTool(ID_REDO, "Redo", getBitmap(wx.wxART_REDO, wx.wxART_TOOLBAR, toolBmpSize), "Redo last undo")
toolBar:AddSeparator()
toolBar:AddTool(ID_FIND, "Find", wx.wxArtProvider.GetBitmap(wx.wxART_FIND, wx.wxART_TOOLBAR, toolBmpSize), "Find text")
toolBar:AddTool(ID_REPLACE, "Replace", wx.wxArtProvider.GetBitmap(wx.wxART_FIND_AND_REPLACE, wx.wxART_TOOLBAR, toolBmpSize), "Find and replace text")
toolBar:AddTool(ID_FIND, "Find", getBitmap(wx.wxART_FIND, wx.wxART_TOOLBAR, toolBmpSize), "Find text")
toolBar:AddTool(ID_REPLACE, "Replace", getBitmap(wx.wxART_FIND_AND_REPLACE, wx.wxART_TOOLBAR, toolBmpSize), "Find and replace text")
toolBar:AddSeparator()
toolBar:AddTool(ID "debug.projectdir.fromfile", "Update", wx.wxArtProvider.GetBitmap(wx.wxART_GO_DIR_UP , wx.wxART_TOOLBAR, toolBmpSize), "Sets projectdir from file")
toolBar:AddTool(ID "debug.projectdir.fromfile", "Update", getBitmap(wx.wxART_GO_DIR_UP , wx.wxART_TOOLBAR, toolBmpSize), "Sets projectdir from file")
toolBar:AddSeparator()
toolBar:AddControl(funclist)
toolBar:Realize()

View File

@@ -53,6 +53,7 @@ ID_BREAK = NewID()
ID_TRACE = NewID()
ID_VIEWCALLSTACK = NewID()
ID_VIEWWATCHWINDOW = NewID()
ID_FULLSCREEN = NewID()
ID_CLEAROUTPUT = NewID()
ID_PROJECTDIR = NewID()
ID_INTERPRETER = NewID()

View File

@@ -66,11 +66,16 @@ function M.show_warnings(top_ast)
if name ~= 'self' then
local func = parent.parent and parent.parent.parent
local assignment = not func.tag or func.tag == 'Set' or func.tag == 'Localrec'
local fname = assignment and type(func[1][1][1]) == 'string' and func[1][1][1]
local func1 = func[1][1]
local fname = assignment and func1 and type(func1[1]) == 'string' and func1[1]
or (func1.tag == 'Index' and func1[1][1] .. '.' .. func1[2][1])
-- "function foo(bar)" => func.tag == 'Set'
-- `Set{{`Id{"foo"}},{`Function{{`Id{"bar"}},{}}}}
-- "local function foo(bar)" => func.tag == 'Localrec'
-- "local _, foo = 1, function(bar)" => func.tag == 'Local'
-- "print(function(bar) end)" => func.tag == nil
-- "function tbl:foo(bar)" => func.tag == 'Set'
-- `Set{{`Index{`Id{"tbl"},`String{"foo"}}},{`Function{{`Id{"self"},`Id{"bar"}},{}}}}
warn("unused parameter '" .. name .. "'" ..
(func and assignment
and (fname and func.tag

View File

@@ -46,10 +46,20 @@ ide.iofilters["GermanUtf8Ascii"] = {
}
ide.iofilters["0d0d0aFix"] = {
-- this function converts 0d0d0a line ending to 0d0a
input = function(fpath, content)
return content:gsub("\013\013\010","\013\010")
end,
}
--üäß
for i,filter in pairs(ide.iofilters) do
assert(filter.output("",filter.input("","äöüÄÖÜß")),"„”äöüÄÖÜß","UTF8-ANSI conversion failed: "..(i))
if filter.input and filter.output then
assert(filter.output("",filter.input("","äöüÄÖÜß")),
"„”äöüÄÖÜß","UTF8-ANSI conversion failed: "..(i))
end
end
-- which: "input" or "output"

View File

@@ -5,12 +5,13 @@ local styles = ide.config.styles
local comment = styles.comment
local MD_MARK_ITAL = '_' -- italic
local MD_MARK_BOLD = '**' -- bold
local MD_MARK_LINK = '[' -- link
local MD_MARK_LINT = ')' -- link terminator
local MD_MARK_LINK = '[' -- link description start
local MD_MARK_LINZ = ']' -- link description end
local MD_MARK_LINA = '(' -- link URL start
local MD_MARK_LINT = ')' -- link URL end
local MD_MARK_HEAD = '#' -- header
local MD_MARK_CODE = '`' -- code
local MD_MARK_BOXD = '|' -- highlight
local MD_MARK_LSEP = '](' -- link separator (between text and link)
local MD_MARK_MARK = ' ' -- separator
local MD_LINK_NEWWINDOW = '+' -- indicator to open a new window for links
local markup = {
@@ -45,11 +46,12 @@ function MarkupHotspotClick(pos, editor)
pos = pos + #MD_MARK_LINK - editor:PositionFromLine(line) -- turn into relative position
-- extract the URL/command on the right side of the separator
local _,_,text = string.find(tx, q(MD_MARK_LSEP).."([^%s]+)"..q(MD_MARK_LINT), pos)
local _,_,text = string.find(tx, q(MD_MARK_LINZ).."(%b"..MD_MARK_LINA..MD_MARK_LINT..")", pos)
if text then
text = text:gsub("^"..q(MD_MARK_LINA), ""):gsub(q(MD_MARK_LINT).."$", "")
local filepath = ide.openDocuments[editor:GetId()].filePath
local _,_,shell = string.find(text, [[^macro:shell%((.*%S)%)$]])
local _,_,http = string.find(text, [[^(http:%S+)$]])
local _,_,http = string.find(text, [[^(https?:%S+)$]])
local _,_,command = string.find(text, [[^macro:(%w+)$]])
if shell then
ShellExecuteCode(shell)
@@ -59,7 +61,7 @@ function MarkupHotspotClick(pos, editor)
ProjectDebug()
elseif http then -- open the URL in a new browser window
wx.wxLaunchDefaultBrowser(http, 0)
else
elseif filepath then -- only check for saved files
-- check if requested to open in a new window
local newwindow = string.find(text, MD_LINK_NEWWINDOW, 1, true) -- plain search
if newwindow then text = string.gsub(text, "^%" .. MD_LINK_NEWWINDOW, "") end
@@ -70,6 +72,7 @@ function MarkupHotspotClick(pos, editor)
filename:Normalize() -- remove .., ., and other similar elements
if filename:FileExists() and
(newwindow or SaveModifiedDialog(editor, true) ~= wx.wxID_CANCEL) then
if not newwindow and ide.osname == 'Macintosh' then editor:GotoPos(0) end
LoadFile(filename,not newwindow and editor or nil,true)
end
end
@@ -96,10 +99,10 @@ local function ismarkup (tx)
-- [%w%p] set is needed to avoid continuing this markup to the next line
s,e,cap = string.find(tx,"^("..q(MD_MARK_HEAD)..".+[%w%p])")
elseif sep == MD_MARK_LINK then
-- allow everything except spaces in the second part
s,e,cap = string.find(tx,"^("..q(MD_MARK_LINK)..nonspace..".-"..nonspace
..q(MD_MARK_LSEP).."[^%s]+"
..q(MD_MARK_LINT)..")", st)
-- allow everything based on balanced link separators
s,e,cap = string.find(tx,
"^(%b"..MD_MARK_LINK..MD_MARK_LINZ
.."%b"..MD_MARK_LINA..MD_MARK_LINT..")", st)
elseif markup[sep] then
-- try 2+ characters between separators first
-- if not found, try a single character
@@ -144,7 +147,9 @@ function MarkupStyle(editor, lines, linee)
if (f) then
local p = ls+f+off
local s = bit.band(editor:GetStyleAt(p), 31)
if iscomment[s] then
-- only style comments and only those that are not at the beginning
-- of the file to avoid styling shebang (#!) lines
if iscomment[s] and p > 0 then
local smark = #mark
local emark = #mark -- assumes end mark is the same length as start mark
if mark == MD_MARK_HEAD then
@@ -152,7 +157,7 @@ function MarkupStyle(editor, lines, linee)
local _,_,full = string.find(w,"^("..q(MD_MARK_HEAD).."+)")
smark,emark = #full,0
elseif mark == MD_MARK_LINK then
local lsep = w:find(q(MD_MARK_LSEP))
local lsep = w:find(q(MD_MARK_LINZ)..q(MD_MARK_LINA))
if lsep then emark = #w-lsep+#MD_MARK_LINT end
end
editor:StartStyling(p, 31)

View File

@@ -30,21 +30,46 @@ menuBar:Append(editMenu, "&Edit")
editMenu:Check(ID_AUTOCOMPLETE_ENABLE, ide.config.autocomplete)
function OnUpdateUIEditMenu(event) -- enable if there is a valid focused editor
local function getControlWithFocus()
local editor = GetEditor()
event:Enable(editor ~= nil)
for _,e in pairs({frame.bottomnotebook.shellbox, frame.bottomnotebook.errorlog}) do
local ctrl = e:FindFocus()
if ctrl and
(ctrl:GetId() == e:GetId()
or ide.osname == 'Macintosh' and
ctrl:GetParent():GetId() == e:GetId()) then editor = e end
end
return editor
end
local othereditors = { frame.bottomnotebook.shellbox, frame.bottomnotebook.errorlog }
function OnUpdateUIEditMenu(event)
local editor = getControlWithFocus()
if editor == nil then event:Enable(false); return end
local menu_id = event:GetId()
local enable =
-- buggy GTK clipboard runs eventloop and can generate asserts
menu_id == ID_PASTE and (wx.__WXGTK__ or editor:CanPaste()) or
menu_id == ID_UNDO and editor:CanUndo() or
menu_id == ID_REDO and editor:CanRedo() or
(menu_id ~= ID_PASTE and menu_id ~= ID_UNDO and menu_id ~= ID_REDO)
-- wxComboBox doesn't have SELECT ALL, so disable it
if editor:GetClassInfo():GetClassName() == 'wxComboBox'
and menu_id == ID_SELECTALL then enable = false end
event:Enable(enable)
end
function OnEditMenu(event)
local menu_id = event:GetId()
local editor = GetEditor()
for _,e in pairs(othereditors) do
if e:FindFocus():GetId() == e:GetId() then editor = e end
end
if editor == nil then return end
local editor = getControlWithFocus()
-- if there is no editor, or if it's not the editor we care about,
-- then allow normal processing to take place
if editor == nil or
editor:FindFocus():GetId() ~= editor:GetId() or
editor:GetClassInfo():GetClassName() ~= 'wxStyledTextCtrl'
then event:Skip(); return end
local menu_id = event:GetId()
if menu_id == ID_CUT then editor:Cut()
elseif menu_id == ID_COPY then editor:Copy()
elseif menu_id == ID_PASTE then editor:Paste()
@@ -54,36 +79,10 @@ function OnEditMenu(event)
end
end
frame:Connect(ID_CUT, wx.wxEVT_COMMAND_MENU_SELECTED, OnEditMenu)
frame:Connect(ID_CUT, wx.wxEVT_UPDATE_UI, OnUpdateUIEditMenu)
frame:Connect(ID_COPY, wx.wxEVT_COMMAND_MENU_SELECTED, OnEditMenu)
frame:Connect(ID_COPY, wx.wxEVT_UPDATE_UI, OnUpdateUIEditMenu)
frame:Connect(ID_PASTE, wx.wxEVT_COMMAND_MENU_SELECTED, OnEditMenu)
frame:Connect(ID_PASTE, wx.wxEVT_UPDATE_UI,
function (event)
local editor = GetEditor()
-- buggy GTK clipboard runs eventloop and can generate asserts
event:Enable(editor and (wx.__WXGTK__ or editor:CanPaste()))
end)
frame:Connect(ID_SELECTALL, wx.wxEVT_COMMAND_MENU_SELECTED, OnEditMenu)
frame:Connect(ID_SELECTALL, wx.wxEVT_UPDATE_UI, OnUpdateUIEditMenu)
frame:Connect(ID_UNDO, wx.wxEVT_COMMAND_MENU_SELECTED, OnEditMenu)
frame:Connect(ID_UNDO, wx.wxEVT_UPDATE_UI,
function (event)
local editor = GetEditor()
event:Enable(editor and editor:CanUndo())
end)
frame:Connect(ID_REDO, wx.wxEVT_COMMAND_MENU_SELECTED, OnEditMenu)
frame:Connect(ID_REDO, wx.wxEVT_UPDATE_UI,
function (event)
local editor = GetEditor()
event:Enable(editor and editor:CanRedo())
end)
for _, event in pairs({ID_CUT, ID_COPY, ID_PASTE, ID_SELECTALL, ID_UNDO, ID_REDO}) do
frame:Connect(event, wx.wxEVT_COMMAND_MENU_SELECTED, OnEditMenu)
frame:Connect(event, wx.wxEVT_UPDATE_UI, OnUpdateUIEditMenu)
end
frame:Connect(ID "edit.cleardynamics", wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
@@ -93,54 +92,18 @@ frame:Connect(ID "edit.cleardynamics", wx.wxEVT_COMMAND_MENU_SELECTED,
frame:Connect(ID "edit.showtooltip", wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
local editor = GetEditor()
local pos = editor:GetCurrentPos()
local line = editor:GetCurrentLine()
local linetx = editor:GetLine(line)
local linestart = editor:PositionFromLine(line)
local localpos = pos-linestart
local linetxtopos = linetx:sub(1,localpos)
linetxtopos = linetxtopos..")"
linetxtopos = linetxtopos:match("([a-zA-Z_0-9%.%:]+)%b()$")
local tip = linetxtopos and GetTipInfo(editor,linetxtopos.."(",false)
if tip then
if(editor:CallTipActive()) then
editor:CallTipCancel()
end
editor:CallTipShow(pos,tip)
if (editor:CallTipActive()) then
editor:CallTipCancel()
return
end
EditorCallTip(editor, editor:GetCurrentPos())
end)
frame:Connect(ID_AUTOCOMPLETE, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
local editor = GetEditor()
if (editor == nil or not editor.spec) then return end
-- retrieve the current line and get a string to the current cursor position in the line
local pos = editor:GetCurrentPos()
local line = editor:GetCurrentLine()
local linetx = editor:GetLine(line)
local linestart = editor:PositionFromLine(line)
local localpos = pos-linestart
local lt = linetx:sub(1,localpos)
lt = lt:gsub("%s*("..editor.spec.sep..")%s*",function(a) return a end)
lt = lt:gsub("%s*%b[]%s*","")
lt = lt:gsub("%s*%b()%s*","")
lt = lt:gsub("%s*%b{}%s*","")
lt = lt:match("[^%[%(%s]*$")
lt = lt:gsub("%s","")
-- know now which string is to be completed
local userList = CreateAutoCompList(editor,lt)
if userList and string.len(userList) > 0 then
editor:UserListShow(1, userList)
--ShowList(userList)
elseif (editor:AutoCompActive()) then
editor:AutoCompCancel()
end
EditorAutoComplete(GetEditor())
end)
frame:Connect(ID_AUTOCOMPLETE, wx.wxEVT_UPDATE_UI, OnUpdateUIEditMenu)

View File

@@ -7,7 +7,6 @@ local ide = ide
local frame = ide.frame
local menuBar = frame.menuBar
local openDocuments = ide.openDocuments
local debugger = ide.debugger
local fileMenu = wx.wxMenu({
{ ID_NEW, "&New\tCtrl-N", "Create an empty document" },

View File

@@ -49,9 +49,9 @@ local debugTab = {
{ ID_ATTACH_DEBUG, "&Start Debugger Server", "Allow a client to start a debugging session" },
{ },
{ ID_STOP_DEBUG, "S&top Debugging\tShift-F12", "Stop the currently running process" },
{ ID_STEP, "St&ep\tF11", "Step into the next line" },
{ ID_STEP_OVER, "Step &Over\tF10", "Step over the next line" },
{ ID_STEP_OUT, "Step O&ut\tShift-F10", "Step out of the current function" },
{ ID_STEP, "Step &Into\tF10", "Step into the next line" },
{ ID_STEP_OVER, "Step &Over\tShift-F10", "Step over the next line" },
{ ID_STEP_OUT, "Step O&ut\tCtrl-F10", "Step out of the current function" },
{ ID_TRACE, "Tr&ace", "Trace execution showing each executed line" },
{ ID_BREAK, "&Break\tShift-F9", "Stop execution of the program at the next executed line of code" },
{ },
@@ -62,7 +62,7 @@ local debugTab = {
local debugMenu = wx.wxMenu(debugTab)
local debugMenuRun = {start="Start &Debugging\tF5", continue="Co&ntinue\tF5"}
local debugMenuStop = {debugging="S&top Debugging\tShift-F12", process="S&top Process\tShift-F12"}
local debugMenuStop = {debugging="S&top Debugging\tShift-F5", process="S&top Process\tShift-F5"}
local targetDirMenu = wx.wxMenu{
{ID "debug.projectdir.choose","Choose ..."},
@@ -129,11 +129,17 @@ frame:Connect(ID "debug.projectdir.fromfile", wx.wxEVT_COMMAND_MENU_SELECTED,
-- Interpreter Selection and Running
local function selectInterpreter(id)
for i,inter in pairs(interpreters) do
menuBar:Check(i, false)
for id in pairs(interpreters) do
menuBar:Check(id, false)
menuBar:Enable(id, true)
end
menuBar:Check(id, true)
menuBar:Enable(id, false)
ide.interpreter = interpreters[id]
if DebuggerShutdown then DebuggerShutdown() end
ide.frame.statusBar:SetStatusText(ide.interpreter.name or "", 5)
ReloadLuaAPI()
end
@@ -143,9 +149,8 @@ function ProjectSetInterpreter(name)
selectInterpreter(id)
end
local function evSelectInterpreter (event)
local chose = event:GetId()
selectInterpreter(chose)
local function evSelectInterpreter(event)
selectInterpreter(event:GetId())
end
for id,inter in pairs(interpreters) do
@@ -203,8 +208,7 @@ end
function ProjectRun(skipcheck)
local fname = getNameToRun(skipcheck)
if not fname then return end
runInterpreter(fname)
return true
return runInterpreter(fname)
end
local debuggers = {
@@ -223,7 +227,7 @@ function ProjectDebug(skipcheck, debtype)
format(ide.debugger.hostname, ide.debugger.portnumber)
local fname = getNameToRun(skipcheck)
if not fname then return end
runInterpreter(fname, debcall)
return runInterpreter(fname, debcall) -- this may be pid or nil
end
return true
end
@@ -282,7 +286,6 @@ frame:Connect(ID_RUNNOW, wx.wxEVT_UPDATE_UI,
frame:Connect(ID_ATTACH_DEBUG, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
ClearAllCurrentLineMarkers()
if (ide.interpreter.fattachdebug) then ide.interpreter:fattachdebug() end
end)
frame:Connect(ID_ATTACH_DEBUG, wx.wxEVT_UPDATE_UI,
@@ -310,7 +313,6 @@ frame:Connect(ID_START_DEBUG, wx.wxEVT_UPDATE_UI,
frame:Connect(ID_STOP_DEBUG, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
ClearAllCurrentLineMarkers()
DebuggerShutdown()
end)
frame:Connect(ID_STOP_DEBUG, wx.wxEVT_UPDATE_UI,

View File

@@ -23,33 +23,35 @@ local findMenu = wx.wxMenu{
{ ID_SORT, "&Sort", "Sort selected lines"}}
menuBar:Append(findMenu, "&Search")
function OnUpdateUISearchMenu(event) event:Enable(GetEditor() ~= nil) end
frame:Connect(ID_FIND, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
findReplace:GetSelectedString()
findReplace:Show(false)
end)
frame:Connect(ID_FIND, wx.wxEVT_UPDATE_UI, OnUpdateUIEditMenu)
frame:Connect(ID_FIND, wx.wxEVT_UPDATE_UI, OnUpdateUISearchMenu)
frame:Connect(ID_REPLACE, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
findReplace:GetSelectedString()
findReplace:Show(true)
end)
frame:Connect(ID_REPLACE, wx.wxEVT_UPDATE_UI, OnUpdateUIEditMenu)
frame:Connect(ID_REPLACE, wx.wxEVT_UPDATE_UI, OnUpdateUISearchMenu)
frame:Connect(ID_FIND_IN_FILES, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
findReplace:GetSelectedString()
findReplace:Show(false,true)
end)
frame:Connect(ID_FIND_IN_FILES, wx.wxEVT_UPDATE_UI, OnUpdateUIEditMenu)
frame:Connect(ID_FIND_IN_FILES, wx.wxEVT_UPDATE_UI, OnUpdateUISearchMenu)
frame:Connect(ID_REPLACE_IN_FILES, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
findReplace:GetSelectedString()
findReplace:Show(true,true)
end)
frame:Connect(ID_REPLACE_IN_FILES, wx.wxEVT_UPDATE_UI, OnUpdateUIEditMenu)
frame:Connect(ID_REPLACE_IN_FILES, wx.wxEVT_UPDATE_UI, OnUpdateUISearchMenu)
frame:Connect(ID_FINDNEXT, wx.wxEVT_COMMAND_MENU_SELECTED, function (event) findReplace:GetSelectedString() findReplace:FindString() end)
frame:Connect(ID_FINDNEXT, wx.wxEVT_UPDATE_UI, function (event) findReplace:HasText() end)
@@ -73,7 +75,7 @@ frame:Connect(ID_GOTOLINE, wx.wxEVT_COMMAND_MENU_SELECTED,
editor:GotoLine(linenum-1)
end
end)
frame:Connect(ID_GOTOLINE, wx.wxEVT_UPDATE_UI, OnUpdateUIEditMenu)
frame:Connect(ID_GOTOLINE, wx.wxEVT_UPDATE_UI, OnUpdateUISearchMenu)
frame:Connect(ID_SORT, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
@@ -87,4 +89,4 @@ frame:Connect(ID_SORT, wx.wxEVT_COMMAND_MENU_SELECTED,
editor:ReplaceSelection(table.concat(buf,"\n"))
end
end)
frame:Connect(ID_SORT, wx.wxEVT_UPDATE_UI, OnUpdateUIEditMenu)
frame:Connect(ID_SORT, wx.wxEVT_UPDATE_UI, OnUpdateUISearchMenu)

View File

@@ -6,9 +6,7 @@ local frame = ide.frame
local menuBar = frame.menuBar
local uimgr = frame.uimgr
local debugger = ide.debugger
local viewMenu = wx.wxMenu{
local viewMenu = wx.wxMenu {
-- NYI { ID "view.preferences", "&Preferences...", "Brings up dialog for settings (TODO)" },
-- NYI { },
{ ID "view.filetree.show", "Project/&FileTree Window\tCtrl-Shift-P", "View the project/filetree window" },
@@ -17,7 +15,7 @@ local viewMenu = wx.wxMenu{
{ ID_VIEWCALLSTACK, "&Stack Window\tCtrl-Shift-S", "View the Stack window" },
{ },
{ ID "view.defaultlayout", "&Default Layout", "Reset to default layout"},
{ ID "view.fullscreen", "Full &Screen\tCtrl-Shift-A", "Switch to or from full screen mode"},
{ ID_FULLSCREEN, "Full &Screen\tCtrl-Shift-A", "Switch to or from full screen mode"},
{ ID "view.style.loadconfig", "&Load Config Style...", "Load and apply style from config file (must contain .styles)"},
}
menuBar:Append(viewMenu, "&View")
@@ -47,8 +45,9 @@ frame:Connect(ID "view.filetree.show", wx.wxEVT_COMMAND_MENU_SELECTED,
uimgr:Update()
end)
frame:Connect(ID "view.fullscreen", wx.wxEVT_COMMAND_MENU_SELECTED,
function (event) ShowFullScreen(not frame:IsFullScreen()) end)
frame:Connect(ID_FULLSCREEN, wx.wxEVT_COMMAND_MENU_SELECTED, function ()
pcall(function() ShowFullScreen(not frame:IsFullScreen()) end)
end)
frame:Connect(ID_VIEWWATCHWINDOW, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event) DebuggerCreateWatchWindow() end)

View File

@@ -13,8 +13,8 @@ local INPUT_MARKER = 3
local INPUT_MARKER_VALUE = 2^INPUT_MARKER
errorlog:Show(true)
errorlog:SetFont(ide.ofont)
errorlog:StyleSetFont(wxstc.wxSTC_STYLE_DEFAULT, ide.ofont)
errorlog:SetFont(ide.font.oNormal)
errorlog:StyleSetFont(wxstc.wxSTC_STYLE_DEFAULT, ide.font.oNormal)
errorlog:StyleClearAll()
errorlog:SetMarginWidth(1, 16) -- marker margin
errorlog:SetMarginType(1, wxstc.wxSTC_MARGIN_SYMBOL);
@@ -22,13 +22,12 @@ errorlog:MarkerDefine(CURRENT_LINE_MARKER, wxstc.wxSTC_MARK_ARROWS, wx.wxBLACK,
errorlog:MarkerDefine(INPUT_MARKER, wxstc.wxSTC_MARK_CHARACTER+string.byte('>'),
wx.wxColour(127, 127, 127), wx.wxColour(240, 240, 240))
errorlog:SetReadOnly(true)
StylesApplyToEditor(ide.config.stylesoutshell,errorlog,ide.ofont,ide.ofontItalic)
StylesApplyToEditor(ide.config.stylesoutshell,errorlog,ide.font.oNormal,ide.font.oItalic)
function ClearOutput()
local current = errorlog:GetReadOnly()
errorlog:SetReadOnly(false)
errorlog:ClearAll()
errorlog:SetReadOnly(current)
errorlog:SetReadOnly(true)
end
function DisplayOutputNoMarker(...)
@@ -80,21 +79,29 @@ end
-- logic to "unhide" wxwidget window using winapi
pcall(function () return require 'winapi' end)
local pid = nil
local function unHideWxWindow(pidAssign)
local function unHideWindow(pidAssign)
-- skip if not configured to do anything
if not ide.config.unhidewxwindow then return end
if not ide.config.unhidewindow then return end
if pidAssign then
pid = pidAssign > 0 and pidAssign or nil
end
if pid and winapi then
local win = winapi.find_window_ex(function(w)
local wins = winapi.find_all_windows(function(w)
return w:get_process():get_pid() == pid
and w:get_class_name() == 'wxWindowClassNR'
and ide.config.unhidewindow[w:get_class_name()]
end)
if win and not win:is_visible() then
win:show()
notebook:SetFocus() -- set focus back to the IDE window
pid = nil
for _,win in pairs(wins) do
-- win:get_class_name() can return nil if the window is already gone
-- between getting the list and this check
local show = (ide.config.unhidewindow[win:get_class_name()] or 0) > 0
if show and not win:is_visible()
or not show and win:is_visible() then
-- use show_async call (ShowWindowAsync) to avoid blocking the IDE
-- if the app is busy or is being debugged
win:show_async(show and winapi.SW_SHOW or winapi.SW_HIDE)
notebook:SetFocus() -- set focus back to the IDE window
pid = nil
end
end
end
end
@@ -110,10 +117,9 @@ function CommandLineRun(cmd,wdir,tooutput,nohide,stringcallback,uid,endcallback)
-- try to extract the name of the executable from the command
-- the executable may not have the extension and may be in quotes
local exename = string.gsub(cmd, "\\", "/")
local _,_,fullname = string.find(exename,'^[\'"]([^\'"]-)[\'"]')
exename = string.match(fullname or exename,'/?([^/]+)%s')
or string.match(fullname or exename,'/?([^/]+)$')
or fullname or exename
local _,_,fullname = string.find(exename,'^[\'"]([^\'"]+)[\'"]')
exename = fullname and string.match(fullname,'/?([^/]+)$')
or string.match(exename,'/?([^/]-)%s') or exename
uid = uid or exename
@@ -125,15 +131,8 @@ function CommandLineRun(cmd,wdir,tooutput,nohide,stringcallback,uid,endcallback)
DisplayOutput(("Program starting as '%s'.\n"):format(cmd))
local proc = nil
local customproc
if (tooutput) then
customproc = wx.wxProcess(errorlog)
customproc:Redirect()
proc = customproc
end
local proc = wx.wxProcess(errorlog)
if (tooutput) then proc:Redirect() end -- redirect the output if requested
-- manipulate working directory
local oldcwd
@@ -156,13 +155,12 @@ function CommandLineRun(cmd,wdir,tooutput,nohide,stringcallback,uid,endcallback)
-- a new process, but connected to the running one (e.g. DDE under Windows).
if not pid or pid == -1 or pid == 0 then
DisplayOutput(("Program unable to run as '%s'\n"):format(cmd))
customproc = nil
return
end
DisplayOutput(("Program '%s' started in '%s' (pid: %d).\n")
:format(uid, (wdir and wdir or wx.wxFileName.GetCwd()), pid))
customprocs[pid] = {proc=customproc, uid=uid, endcallback=endcallback, started = os.clock()}
customprocs[pid] = {proc=proc, uid=uid, endcallback=endcallback, started = TimeGet()}
local streamin = proc and proc:GetInputStream()
local streamerr = proc and proc:GetErrorStream()
@@ -177,7 +175,7 @@ function CommandLineRun(cmd,wdir,tooutput,nohide,stringcallback,uid,endcallback)
streamouts[pid] = {stream=streamout, callback=stringcallback, out=true}
end
unHideWxWindow(pid)
unHideWindow(pid)
nameTab(errorlog, "Output (running)")
return pid
@@ -217,7 +215,6 @@ local function getStreams()
(getInputLine() > -1 or errorlog:GetReadOnly()) then
ActivateOutput()
updateInputMarker()
errorlog:SetFocus()
end
pfn = pfn and pfn()
end
@@ -251,10 +248,12 @@ errorlog:Connect(wx.wxEVT_END_PROCESS, function(event)
-- delete markers and set focus to the editor if there is an input marker
if errorlog:MarkerPrevious(errorlog:GetLineCount(), INPUT_MARKER_VALUE) > -1 then
errorlog:MarkerDeleteAll(INPUT_MARKER)
GetEditor():SetFocus()
local editor = GetEditor()
-- check if editor still exists; it may not if the window is closed
if editor then editor:SetFocus() end
end
nameTab(errorlog, "Output")
local runtime = os.clock() - customprocs[pid].started
local runtime = TimeGet() - customprocs[pid].started
streamins[pid] = nil
streamerrs[pid] = nil
@@ -263,7 +262,7 @@ errorlog:Connect(wx.wxEVT_END_PROCESS, function(event)
customprocs[pid].endcallback()
end
customprocs[pid] = nil
unHideWxWindow(0)
unHideWindow(0)
DebuggerStop()
DisplayOutput(("Program completed in %.2f seconds (pid: %d).\n")
:format(runtime, pid))
@@ -272,18 +271,18 @@ errorlog:Connect(wx.wxEVT_END_PROCESS, function(event)
errorlog:Connect(wx.wxEVT_IDLE, function()
if (#streamins or #streamerrs) then getStreams() end
unHideWxWindow()
unHideWindow()
end)
local jumptopatterns = {
-- <filename>(line,linepos):
"%s*([%w:/%\\_%-%.]+)%((%d+),(%d+)%)%s*:",
"^%s*(.-)%((%d+),(%d+)%)%s*:",
-- <filename>(line):
"%s*([%w:/%\\_%-%.]+)%((%d+).*%)%s*:",
-- <filename>:line:
"%s*([%w:/%\\_%-%.]+):(%d+)%s*:",
"^%s*(.-)%((%d+).*%)%s*:",
--[string "<filename>"]:line:
'.*%[string "([%w:/%\\_%-%.]+)"%]:(%d+)%s*:',
'^.-%[string "([^"]+)"%]:(%d+)%s*:',
-- <filename>:line:
"^%s*(.-):(%d+)%s*:",
}
errorlog:Connect(wxstc.wxEVT_STC_DOUBLECLICK,

View File

@@ -233,7 +233,6 @@ end
-----------------------------------
local function saveNotebook(nb)
local cnt = nb:GetPageCount()
@@ -250,7 +249,6 @@ local function saveNotebook(nb)
for i=1,cnt do
local id = nb:GetPageText(i-1)
local pg = nb:GetPage(i-1)
local x,y = pg:GetPosition():GetXY()
addTo(pagesX,x,id)
@@ -303,14 +301,14 @@ local function loadNotebook(nb,str,fnIdConvert)
if (not str) then return end
local cnt = nb:GetPageCount()
local sel = nb:GetSelection()
-- store old pages
local currentpages = {}
for i=1,cnt do
local id = nb:GetPageText(i-1)
local newid = fnIdConvert and fnIdConvert(id) or id
currentpages[newid] = {page = nb:GetPage(i-1), text = id, index = i-1}
currentpages[newid] = currentpages[newid] or {}
table.insert(currentpages[newid], {page = nb:GetPage(i-1), text = id, index = i-1})
end
-- remove them
@@ -318,7 +316,7 @@ local function loadNotebook(nb,str,fnIdConvert)
nb:RemovePage(i-1)
end
-- readd them and perform splits
-- read them and perform splits
local direction
local splits = {
X = wx.wxRIGHT,
@@ -337,13 +335,13 @@ local function loadNotebook(nb,str,fnIdConvert)
local instr = cmd:match("<(%w)>")
if (not instr) then
local id = fnIdConvert and fnIdConvert(cmd) or cmd
local page = currentpages[id]
if (page) then
local pageind = next(currentpages[id] or {})
if (pageind) then
local page = currentpages[id][pageind]
currentpages[id][pageind] = nil
nb:AddPage(page.page, page.text)
currentpages[id] = nil
if (direction) then
nb:Split(t, direction)
end
if (direction) then nb:Split(t, direction) end
finishPage(page)
end
end
@@ -351,18 +349,18 @@ local function loadNotebook(nb,str,fnIdConvert)
end
-- add anything we forgot
for i,page in pairs(currentpages) do
nb:AddPage(page.page, page.text)
finishPage(page)
for _,pagelist in pairs(currentpages) do
for _,page in pairs(pagelist) do
nb:AddPage(page.page, page.text)
finishPage(page)
end
end
if (newsel) then
nb:SetSelection(newsel)
end
end
function SettingsRestoreView()
local listname = "/view"
local path = settings:GetPath()
@@ -424,6 +422,7 @@ function SettingsRestoreEditorSettings()
ide.config.interpreter = settingsReadSafe(settings,"interpreter",ide.config.interpreter)
ProjectSetInterpreter(ide.config.interpreter)
end
function SettingsSaveEditorSettings()
local listname = "/editor"
local path = settings:GetPath()

View File

@@ -11,8 +11,8 @@ local out = bottomnotebook.shellbox
local OUTPUT_MARKER = 3
local remotesend
out:SetFont(ide.ofont)
out:StyleSetFont(wxstc.wxSTC_STYLE_DEFAULT, ide.ofont)
out:SetFont(ide.font.oNormal)
out:StyleSetFont(wxstc.wxSTC_STYLE_DEFAULT, ide.font.oNormal)
out:StyleClearAll()
out:SetBufferedDraw(true)
@@ -32,7 +32,7 @@ out:MarkerDefine(BREAKPOINT_MARKER, wxstc.wxSTC_MARK_BACKGROUND, wx.wxBLACK, wx.
out:MarkerDefine(OUTPUT_MARKER, wxstc.wxSTC_MARK_BACKGROUND, wx.wxBLACK, wx.wxColour(240, 240, 240))
out:SetReadOnly(false)
SetupKeywords(out,"lua",nil,ide.config.stylesoutshell,ide.ofont,ide.ofontItalic)
SetupKeywords(out,"lua",nil,ide.config.stylesoutshell,ide.font.oNormal,ide.font.oItalic)
local function getPromptLine()
local totalLines = out:GetLineCount()
@@ -254,6 +254,7 @@ local function executeShellCode(tx)
fn, err = loadstring("return "..tx)
if not forceexpression and err and
(err:find("'<eof>' expected near '") or
err:find("'%(' expected near") or
err:find("unexpected symbol near '")) then
fn, err = loadstring(tx)
addedret = false
@@ -284,7 +285,10 @@ local function executeShellCode(tx)
if addedret then
local mobdebug = require "mobdebug"
for i,v in pairs(res) do -- stringify each of the returned values
res[i] = mobdebug.line(v, {nocode = true, comment = 1})
res[i] = (forceexpression and i > 1 and '\n' or '') ..
mobdebug.line(v, {nocode = true, comment = 1,
-- if '=' is used, then use multi-line serialized output
indent = forceexpression and ' ' or nil})
end
-- add nil only if we are forced (using =) or if this is not a statement
-- this is needed to print 'nil' when asked for 'foo',
@@ -327,7 +331,7 @@ end
local function displayShellIntro()
DisplayShellDirect([[Welcome to the interactive Lua interpreter.
Enter Lua code and press Enter to run it. Use Shift-Enter for multiline code.
Use 'clear' to clear the shell output and the history. Prepend '=' to show values.]])
Use 'clear' to clear the shell output and the history. Prepend '=' to show complex values on multiple lines.]])
DisplayShellPrompt('')
end

View File

@@ -224,9 +224,9 @@ function ReApplySpecAndStyles()
local errorlog = ide.frame.bottomnotebook.errorlog
local shellbox = ide.frame.bottomnotebook.shellbox
SetupKeywords(shellbox,"lua",nil,ide.config.stylesoutshell,ide.ofont,ide.ofontItalic)
SetupKeywords(shellbox,"lua",nil,ide.config.stylesoutshell,ide.font.oNormal,ide.font.oItalic)
StylesApplyToEditor(ide.config.stylesoutshell,errorlog,ide.ofont,ide.ofontItalic)
StylesApplyToEditor(ide.config.stylesoutshell,errorlog,ide.font.oNormal,ide.font.oItalic)
end
function LoadConfigStyle()
@@ -234,7 +234,7 @@ function LoadConfigStyle()
"/cfg",
"",
"Lua file (*.lua)|*.lua|All files (*)|*",
wx.wxOPEN + wx.wxFILE_MUST_EXIST)
wx.wxFD_OPEN + wx.wxFD_FILE_MUST_EXIST)
if fileDialog:ShowModal() == wx.wxID_OK then
local cfg = {wxstc = wxstc, path = {}, editor = {}, view ={}, acandtip = {}, outputshell = {}, debugger={},}
local cfgfn,err = loadfile(fileDialog:GetPath())

View File

@@ -5,8 +5,8 @@
-- that may have other versions present somewhere else in path/cpath
local iswindows = os.getenv('WINDIR') or (os.getenv('OS') or ''):match('[Ww]indows')
package.cpath = (iswindows
and 'bin/?.dll;bin/clibs/?.dll;bin/clibs/?/?.dll;bin/clibs/?/?/?.dll;'
or 'bin/?.so;bin/clibs/?.so;bin/clibs/?/?.so;bin/clibs/?/?/?.so;')
and 'bin/?.dll;bin/clibs/?.dll;'
or 'bin/clibs/?.dylib;bin/lib?.dylib;bin/?.so;bin/clibs/?.so;')
.. package.cpath
package.path = 'lualibs/?.lua;lualibs/?/?.lua;lualibs/?/init.lua;lualibs/?/?/?.lua;lualibs/?/?/init.lua;'
.. package.path
@@ -36,7 +36,12 @@ ide = {
debugger = {
verbose = false,
},
default = {
name = 'untitled',
fullname = 'untitled.lua',
},
outputshell = {},
filetree = {},
styles = StylesGetDefault(),
stylesoutshell = StylesGetDefault(),
@@ -50,7 +55,7 @@ ide = {
},
activateoutput = false, -- activate output/console on Run/Debug/Compile
unhidewxwindow = false, -- try to unhide a wx window
unhidewindow = false, -- to unhide a gui window
allowinteractivescript = false, -- allow interaction in the output window
filehistorylength = 20,
projecthistorylength = 15,
@@ -91,12 +96,32 @@ ide = {
-- modTime = wxDateTime of disk file or nil,
-- isModified = bool is the document modified? }
ignoredFilesList = {},
font = nil,
fontItalic = nil,
ofont = nil,
ofontItalic = nil,
font = {
eNormal = nil,
eItalic = nil,
oNormal = nil,
oItalic = nil,
fNormal = nil,
}
}
function setLuaPaths(mainpath, os)
-- (luaconf.h) in Windows, any exclamation mark ('!') in the path is replaced
-- by the path of the directory of the executable file of the current process.
-- this effectively prevents any path with an exclamation mark from working.
-- if the path has an excamation mark, we allow Lua to expand it
-- (for use in LUA_PATH/LUA_CPATH)
if os == "Windows" and mainpath:find('%!') then mainpath = "!/../" end
wx.wxSetEnv("LUA_PATH", package.path .. ';'
.. mainpath.."lualibs/?/?.lua;"..mainpath.."lualibs/?.lua")
local clibs =
os == "Windows" and mainpath.."bin/?.dll;"..mainpath.."bin/clibs/?.dll" or
os == "Macintosh" and mainpath.."bin/lib?.dylib;"..mainpath.."bin/clibs/?.dylib" or
os == "Unix" and mainpath.."bin/?.so;"..mainpath.."bin/clibs/?.so" or nil
if clibs then wx.wxSetEnv("LUA_CPATH", package.cpath .. ';' .. clibs) end
end
---------------
-- process args
local filenames = {}
@@ -106,15 +131,23 @@ do
local fullPath = arg[1] -- first argument must be the application name
assert(type(fullPath) == "string", "first argument must be application name")
if not wx.wxIsAbsolutePath(fullPath) then
ide.arg = arg
ide.osname = wx.wxPlatformInfo.Get():GetOperatingSystemFamilyName()
-- on Windows use GetExecutablePath, which is Unicode friendly,
-- whereas wxGetCwd() is not (at least in wxlua 2.8.12.2).
-- some wxlua version on windows report wx.dll instead of *.exe.
local exepath = wx.wxStandardPaths.Get():GetExecutablePath()
if ide.osname == "Windows" and exepath:find("%.exe$") then
fullPath = exepath
elseif not wx.wxIsAbsolutePath(fullPath) then
fullPath = wx.wxGetCwd().."/"..fullPath
if wx.__WXMSW__ then fullPath = wx.wxUnix2DosFilename(fullPath) end
end
ide.arg = arg
ide.editorFilename = fullPath
ide.config.path.app = fullPath:match("([%w_-%.]+)$"):gsub("%.[^%.]*$","")
assert(ide.config.path.app, "no application path defined")
for index = 2, #arg do
if (arg[index] == "-cfg" and index+1 <= #arg) then
local str = arg[index+1]
@@ -128,6 +161,8 @@ do
table.insert(filenames,arg[index])
end
end
setLuaPaths(GetPathWithSep(ide.editorFilename), ide.osname)
end
-----------------------
@@ -222,6 +257,7 @@ local function loadSpecs()
spec.sep = spec.sep or ""
spec.iscomment = {}
spec.iskeyword0 = {}
spec.isstring = {}
if (spec.lexerstyleconvert) then
if (spec.lexerstyleconvert.comment) then
for i,s in pairs(spec.lexerstyleconvert.comment) do
@@ -233,6 +269,11 @@ local function loadSpecs()
spec.iskeyword0[s] = true
end
end
if (spec.lexerstyleconvert.stringtxt) then
for i,s in pairs(spec.lexerstyleconvert.stringtxt) do
spec.isstring[s] = true
end
end
end
end
end
@@ -253,6 +294,8 @@ if app.preinit then app.preinit() end
do
addConfig("cfg/user.lua",false)
local home = os.getenv("HOME")
if home then addConfig(home .. "/.zbs/user.lua",false) end
for i,v in ipairs(configs) do
addConfig(v,true,true)
end
@@ -320,10 +363,12 @@ if app.postinit then app.postinit() end
-- app-specific menus (Help/About), which are not recognized by MacOS
-- as special items unless SetMenuBar is done after menus are populated.
ide.frame:SetMenuBar(ide.frame.menuBar)
if ide.osname == 'Macintosh' then -- force refresh to fix the filetree
pcall(function() ide.frame:ShowFullScreen(true) ide.frame:ShowFullScreen(false) end)
end
ide.frame:Show(true)
-- Call wx.wxGetApp():MainLoop() last to start the wxWidgets event loop,
-- otherwise the wxLua program will exit immediately.
-- Does nothing if running from wxLua, wxLuaFreeze, or wxLuaEdit since the
-- MainLoop is already running or will be started by the C++ program.
-- call wx.wxGetApp():MainLoop() last to start the wxWidgets event loop,
-- otherwise the program will exit immediately.
-- Does nothing if the MainLoop is already running.
wx.wxGetApp():MainLoop()

View File

@@ -152,6 +152,7 @@ function GetFileNameExt(filePath)
end
function GetPathWithSep(wxfn)
if type(wxfn) == 'string' then wxfn = wx.wxFileName(wxfn) end
return wxfn:GetPath(bit.bor(wx.wxPATH_GET_VOLUME, wx.wxPATH_GET_SEPARATOR))
end
@@ -168,12 +169,46 @@ function FileSysGet(dir,spec)
end
local f = browse:FindFirst(dir,spec)
while #f>0 do
table.insert(content,f)
table.insert(content,(f:gsub("^file:",""))) -- remove file: protocol (wx2.9+)
f = browse:FindNext()
end
return content
end
function GetFullPathIfExists(p, f)
if not p or not f then return end
local file = wx.wxFileName(f)
-- Normalize call is needed to make the case of p = '/abc/def' and
-- f = 'xyz/main.lua' work correctly. Normalize() returns true if done.
return (file:Normalize(wx.wxPATH_NORM_ALL, p)
and file:FileExists()
and file:GetFullPath())
end
function FileWrite(file,content)
local log = wx.wxLogNull() -- disable error reporting; will report as needed
local file = wx.wxFile(file, wx.wxFile.write)
if not file:IsOpened() then return nil, wx.wxSysErrorMsg() end
file:Write(content, #content)
file:Close()
return true
end
function FileRead(file)
local log = wx.wxLogNull() -- disable error reporting; will report as needed
local file = wx.wxFile(file, wx.wxFile.read)
if not file:IsOpened() then return end
local _, content = file:Read(file:Length())
file:Close()
return content, wx.wxSysErrorMsg()
end
function FileRename(file1, file2) return wx.wxRenameFile(file1, file2) end
TimeGet = pcall(require, "socket") and socket.gettime or os.clock
function pairsSorted(t, f)
local a = {}
for n in pairs(t) do table.insert(a, n) end

View File

@@ -400,8 +400,10 @@ return cgbinpath and {
local function evCompile(event)
local filename,info = GetEditorFileAndCurInfo()
local editor = GetEditor()
local glsl = editor and editor.spec and editor.spec.apitype and editor.spec.apitype == "glsl"
local entryname = (glsl and "main" or info.selword)
if (not (filename and info.selword and cgbinpath)) then
if (not (filename and entryname and cgbinpath)) then
DisplayOutput("Error: Cg Compile: Insufficient parameters (nofile / not selected entry function!\n")
return
end
@@ -415,11 +417,9 @@ return cgbinpath and {
local args = data.customarg and data.custom or ""
args = args:len() > 0 and args or nil
local fullname = filename:GetFullPath()
local glsl = editor and editor.spec and editor.spec.apitype and editor.spec.apitype == "glsl"
local outname = fullname.."."..info.selword.."^"
outname = args and outname..args:gsub("%s+%-",";-")..";^" or outname
local fullname = filename:GetFullPath()
local outname = fullname.."."..entryname.."^"
outname = args and outname..args:gsub("%s*[%-%/]",";-")..";^" or outname
outname = outname..profile[domain]..profile.ext
outname = '"'..outname..'"'
@@ -430,7 +430,7 @@ return cgbinpath and {
cmdline = args and cmdline..args.." " or cmdline
cmdline = cmdline..data.domaindefs[domain]
cmdline = cmdline.."-o "..outname.." "
cmdline = cmdline.."-entry "..info.selword
cmdline = cmdline.."-entry "..entryname
cmdline = cgbinpath.."/cgc.exe"..cmdline

View File

@@ -1,5 +1,46 @@
-- author: Christoph Kubisch
---------------------------------------------------------
local StripCommentsC = StripCommentsC
if not StripCommentsC then
StripCommentsC = function(tx)
local out = ""
local lastc = ""
local skip
local skipline
local skipmulti
local tx = string.gsub(tx, "\r\n", "\n")
for c in tx:gmatch(".") do
local oc = c
local tu = lastc..c
skip = c == '/'
if ( not (skipmulti or skipline)) then
if (tu == "//") then
skipline = true
elseif (tu == "/*") then
skipmulti = true
c = ""
elseif (lastc == '/') then
oc = tu
end
elseif (skipmulti and tu == "*/") then
skipmulti = false
c = ""
elseif (skipline and lastc == "\n") then
out = out.."\n"
skipline = false
end
lastc = c
if (not (skip or skipline or skipmulti)) then
out = out..oc
end
end
return out..lastc
end
end
local function ffiToApi(ffidef)
local str = ffidef
@@ -250,8 +291,16 @@ local function exec(wxfname,projectdir)
editor:SetText(tx)
end
if (RELPATH) then
ffitoapiExec = exec
if (not ide) then
ffitoapi = function(fname)
local f = io.open(fname,"rb")
local tx = f:read("*a")
f:close()
tx = ffiToApi(tx)
local f = io.open(fname,"wb")
f:write(tx)
f:close()
end
end
return {

Binary file not shown.

View File

@@ -1,49 +1,21 @@
CHANGELOG.md
LICENSE
README.md
api/lua/baselib.lua
api/lua/love2d.lua
api/readme.txt
bin/clibs/lfs.dll
bin/clibs/mojoshader.dll
bin/clibs/mime/core.dll
bin/clibs/ssl.dll
bin/clibs/socket/core.dll
bin/clibs/wx/wxlua_msw28_wxbindadv.dll
bin/clibs/wx/wxlua_msw28_wxbindaui.dll
bin/clibs/wx/wxlua_msw28_wxbindbase.dll
bin/clibs/wx/wxlua_msw28_wxbindcore.dll
bin/clibs/wx/wxlua_msw28_wxbindgl.dll
bin/clibs/wx/wxlua_msw28_wxbindhtml.dll
bin/clibs/wx/wxlua_msw28_wxbindmedia.dll
bin/clibs/wx/wxlua_msw28_wxbindnet.dll
bin/clibs/wx/wxlua_msw28_wxbindstc.dll
bin/clibs/wx/wxlua_msw28_wxbindxml.dll
bin/clibs/wx/wxlua_msw28_wxbindxrc.dll
bin/clibs/wx/wxlua_msw28_wxlua.dll
bin/clibs/wx/wxlua_msw28_wxluadebug.dll
bin/clibs/wx/wxlua_msw28_wxluasocket.dll
bin/clibs/zmq.dll
bin/libzmq.dll
bin/lua.exe
bin/lua5.1.dll
bin/lua51.dll
bin/winapi.dll
bin/wx.dll
bin/wxbase28_net_vc_custom.dll
bin/wxbase28_vc_custom.dll
bin/wxbase28_xml_vc_custom.dll
bin/wxmsw28_adv_vc_custom.dll
bin/wxmsw28_aui_vc_custom.dll
bin/wxmsw28_core_vc_custom.dll
bin/wxmsw28_gl_vc_custom.dll
bin/wxmsw28_html_vc_custom.dll
bin/wxmsw28_media_vc_custom.dll
bin/wxmsw28_qa_vc_custom.dll
bin/wxmsw28_richtext_vc_custom.dll
bin/wxmsw28_stc_vc_custom.dll
bin/wxmsw28_xrc_vc_custom.dll
cfg/user-sample.lua
interpreters/love2d.lua
interpreters/luadeb.lua
interpreters/moai.lua
lualibs/copas/copas.lua
lualibs/coxpcall/coxpcall.lua
lualibs/luainspect/ast.lua
@@ -83,6 +55,7 @@ lualibs/socket/tp.lua
lualibs/socket/url.lua
lualibs/ssl.lua
lualibs/ssl/https.lua
lualibs/testwell.lua
spec/lua.lua
src/defs.lua
src/editor/autocomplete.lua

View File

@@ -27,7 +27,11 @@ local app = {
wx.wxArtProvider.Push(artProvider)
ide.config.interpreter = "luadeb"
ide.config.unhidewxwindow = true -- allow unhiding of wx windows
ide.config.unhidewindow = { -- allow unhiding of GUI windows
-- 1 - unhide if hidden, 0 - hide if shown
wxWindowClassNR = 1, -- wxwindows applications
GLUT = 1, -- opengl applications (for example, moai)
}
ide.config.allowinteractivescript = true -- allow interaction in the output window
-- this needs to be in pre-init to load the styles
@@ -60,14 +64,20 @@ local app = {
menuBar:Check(ID_CLEAROUTPUT, true)
-- load welcome.lua from myprograms/ if exists
local fn = wx.wxFileName("myprograms/welcome.lua")
if fn:FileExists() and
(not ide.config.path.projectdir
or string.len(ide.config.path.projectdir) == 0) then
fn:Normalize() -- make absolute path
LoadFile(fn:GetFullPath(),nil,true)
ProjectUpdateProjectDir(fn:GetPath(wx.wxPATH_GET_VOLUME))
-- load myprograms/welcome.lua if exists and no projectdir
local projectdir = ide.config.path.projectdir
if (not projectdir or string.len(projectdir) == 0
or not wx.wxFileName(projectdir):DirExists()) then
local home = wx.wxGetHomeDir():gsub("[\\/]$","")
for _,dir in pairs({home, home.."/Desktop", ""}) do
local fn = wx.wxFileName("myprograms/welcome.lua")
-- normalize to absolute path
if fn:Normalize(wx.wxPATH_NORM_ALL, dir) and fn:FileExists() then
LoadFile(fn:GetFullPath(),nil,true)
ProjectUpdateProjectDir(fn:GetPath(wx.wxPATH_GET_VOLUME))
break
end
end
end
end,
@@ -79,7 +89,6 @@ local app = {
settingsapp = "ZeroBraneStudio",
settingsvendor = "ZeroBraneLLC",
},
}
return app

View File

@@ -1,10 +1,13 @@
editor.fontname = "Courier New"
editor.caretline = true
editor.showfncall = true
editor.autotabs = false
editor.usetabs = false
editor.tabwidth = 2
editor.usewrap = true
editor.calltipdelay = 500
local G = ... -- this now points to the global environment
if G.ide.osname == 'Macintosh' then filetree.fontsize = 11 end
filehistorylength = 20

View File

@@ -55,7 +55,7 @@ local function DisplayAbout(event)
</body>
</html>]]
local dlg = wx.wxDialog(frame, wx.wxID_ANY, "About ZeroBane Studio")
local dlg = wx.wxDialog(frame, wx.wxID_ANY, "About ZeroBrane Studio")
local html = wx.wxLuaHtmlWindow(dlg, wx.wxID_ANY,
wx.wxDefaultPosition, wx.wxSize(440, 270),
wx.wxHW_SCROLLBAR_NEVER)
@@ -73,11 +73,10 @@ local function DisplayAbout(event)
topsizer:Add(html, 1, wx.wxALL, 10)
topsizer:Add(line, 0, wx.wxEXPAND + wx.wxLEFT + wx.wxRIGHT, 10)
topsizer:Add(button, 0, wx.wxALL + wx.wxALIGN_RIGHT, 10)
topsizer:Fit(dlg)
dlg:SetAutoLayout(true)
dlg:SetSizer(topsizer)
topsizer:Fit(dlg)
dlg:ShowModal()
dlg:Destroy()
end

Binary file not shown.

Before

Width:  |  Height:  |  Size: 674 B

After

Width:  |  Height:  |  Size: 1.3 KiB