Compare commits

...

190 Commits
0.20 ... 0.28

Author SHA1 Message Date
Paul Kulchenko
3a18136076 Fixed 'Trace' command to continue working when a debugged file is not activated 2012-03-21 10:16:17 -07:00
Paul Kulchenko
1b057988bc Updated to work with mobdebug v0.44 2012-03-21 10:14:30 -07:00
Paul Kulchenko
92001a4a78 Added option to activate output/console when Run/Debug/Compile commands are executed 2012-03-20 21:25:38 -07:00
Paul Kulchenko
906c70248b Added full screen mode 2012-03-17 21:20:32 -07:00
Paul Kulchenko
4554c67c3e Added killing running process on IDE exit. Allowed killing a running process with Shift-F12. Disabled compilation and debugging when some process is running. 2012-03-10 22:21:36 -08:00
Paul Kulchenko
cb7ee575c7 Fixed an issue with saving a file when no project directory is set 2012-03-10 21:55:31 -08:00
Paul Kulchenko
c758d4c62a Updated MANIFEST with metalua lib 2012-03-09 22:06:18 -08:00
Paul Kulchenko
8c1c06bb16 Fixed missing semicolon in lualibs path; added path for debugger to search under lualibs 2012-03-09 22:01:20 -08:00
Paul Kulchenko
99ca5fe952 Merge branch 'master' of git://estrelaeditor.git.sourceforge.net/gitroot/estrelaeditor/estrelaeditor 2012-03-08 11:49:22 -08:00
Paul Kulchenko
1f064655cc Added metalua library 2012-03-08 11:48:57 -08:00
Paul Kulchenko
9a05cc3678 Fixed missing slash on SaveAs by enforcing trailing slash for the project path 2012-03-08 10:50:47 -08:00
Paul Kulchenko
6da3cb2c32 Disabled buffering of the output for scripts run from IDE 2012-02-27 22:49:00 -08:00
Paul Kulchenko
d2cb7cb1c2 Fixed an issue with a missing path separator, which prevented debugging from executing step commands in some cases 2012-02-22 21:54:36 -08:00
crazybutcher
0ac769ffba bugfix in luxinia1 interpreter 2012-02-16 21:52:35 +01:00
Paul Kulchenko
ef60786e48 Removed debug output when coroutines are edited 2012-02-14 23:35:56 -08:00
Paul Kulchenko
f9c15faab8 Fixed activation of a correct tab when one of the editor tabs is closed 2012-02-13 18:30:45 -08:00
Paul Kulchenko
59b28ef35c Merge branch 'master' of git://estrelaeditor.git.sourceforge.net/gitroot/estrelaeditor/estrelaeditor 2012-02-12 22:42:12 -08:00
Paul Kulchenko
9db7d4ec8a Fixed an issue with file activation from a debugger (files that are 'required' now actiate correctly) 2012-02-12 22:41:41 -08:00
Paul Kulchenko
40eaace714 Disabled dynamic words in the config (zbstudio) 2012-02-10 09:47:05 -08:00
Paul Kulchenko
fe000bb59e Wrapped DragAcceptFiles into a protected call to make it not fail on MacOS (compiled with wxwidgets 2.8.12) 2012-02-09 12:23:47 -08:00
crazybutcher
9aa220df41 Merge branch 'master' of ssh://estrelaeditor.git.sourceforge.net/gitroot/estrelaeditor/estrelaeditor 2012-02-08 20:05:33 +01:00
Paul Kulchenko
97c52f15f3 Added highlight style to markup 2012-02-07 23:41:29 -08:00
Paul Kulchenko
54f578790b Merge branch 'master' of git://estrelaeditor.git.sourceforge.net/gitroot/estrelaeditor/estrelaeditor 2012-02-01 22:29:54 -08:00
Paul Kulchenko
a51a08c1b8 Removed slash conversion in filename on Save; added markup styling on SaveAs 2012-02-01 22:29:28 -08:00
Paul Kulchenko
7620e758a0 Updated error messages to more generic ones 2012-02-01 19:52:55 -08:00
Paul Kulchenko
80da9253dd Normalized the filename path to remove '.' and such 2012-02-01 19:33:08 -08:00
Paul Kulchenko
a133fa900e Fixed the issue of ClosePage method being called with two different parameters 2012-01-31 23:00:55 -08:00
Paul Kulchenko
0fa62e544a Updated markup processing with run and debug commands, http link processing, and opening local files in a new window. Switched from hotspot click event to mouse button processing to avoid the issue with selection being active in a newly loaded page 2012-01-31 22:56:18 -08:00
Paul Kulchenko
601dbef6e5 Added Debug and Run methods to simulate menu commands 2012-01-31 22:49:09 -08:00
unknown
01b3a4fd09 Merge branch 'master' of ssh://estrelaeditor.git.sourceforge.net/gitroot/estrelaeditor/estrelaeditor 2012-01-31 12:08:36 +01:00
crazybutcher
ed0df13acb dx backwards compat mode and replace / in filenames 2012-01-31 12:06:55 +01:00
Paul Kulchenko
642fd63724 Added setting a project folder on initial start (zbstudio) 2012-01-30 18:21:51 -08:00
Paul Kulchenko
a1586cd530 Replaced hardcoded path separater with a method call 2012-01-30 18:19:18 -08:00
Paul Kulchenko
291cba2d79 Merge branch 'master' of git://estrelaeditor.git.sourceforge.net/gitroot/estrelaeditor/estrelaeditor 2012-01-30 15:58:40 -08:00
Paul Kulchenko
96bffc1322 Added markup formatting in the comments 2012-01-30 15:58:28 -08:00
Paul Kulchenko
e88710fbbc Updated debugger to use project dir as basedir if it is specified (rather than the path to the currently edited file) 2012-01-30 15:03:22 -08:00
Paul Kulchenko
99da8be0f8 Fixed the issue of the project dir being returned with two trailing slashes 2012-01-30 15:03:05 -08:00
crazybutcher
c8c654cb2b removed ptx r,g,b,a keywords 2012-01-30 22:05:47 +01:00
crazybutcher
cf68a42547 added nvidia ptx spec 2012-01-30 22:01:57 +01:00
Paul Kulchenko
5c0d4cccdd Added setting the current project directory for the shell to allow 'require' commands to work with local modules 2012-01-29 17:10:55 -08:00
Paul Kulchenko
b979b41688 Fixed an issue with activating the currenly edited file in the file tree 2012-01-29 13:55:59 -08:00
Paul Kulchenko
b807fa9a99 Enforced visibility for shell prompt 2012-01-28 11:59:18 -08:00
Paul Kulchenko
ef5b1b0e09 Removed hardcoded references to the console page/tab 2012-01-28 11:53:56 -08:00
Paul Kulchenko
04a038da45 Moved wrap flags to the line end to make them less noticeable 2012-01-28 11:52:17 -08:00
Paul Kulchenko
bc0e3190d4 Added style processing for font name, font size, visibility and hotspot attributes 2012-01-28 11:20:52 -08:00
Paul Kulchenko
16dcd084e1 Renamed ShellExecuteCode to ...File; added ShellExecuteCode to execute a fragment of code 2012-01-28 10:52:35 -08:00
crazybutcher
15f8c15039 bugfix on close-file 2012-01-25 22:00:28 +01:00
crazybutcher
bff0da36dc minor updates to license (2012) and readme (front-ends explained) 2012-01-21 14:27:03 +01:00
crazybutcher
1e933a6b75 Merge remote-tracking branch 'zbstudio/master' 2012-01-21 14:15:06 +01:00
crazybutcher
c9bb3e01ca added glfw 2.7.2 api and changed luxinia2 to use it instead of glfw3 2012-01-21 14:13:54 +01:00
Paul Kulchenko
e4e5e82660 Disabled attaching debugger by default as this triggers warning to open firewall on the first start, which is inconvenient 2012-01-18 14:00:48 -08:00
Paul Kulchenko
c5f2d3cf18 Merge branch 'master' of git://estrelaeditor.git.sourceforge.net/gitroot/estrelaeditor/estrelaeditor 2012-01-18 10:44:46 -08:00
crazybutcher
017049f473 updated lua.exe to 5.1.4 as well 2012-01-18 19:41:33 +01:00
Paul Kulchenko
75ce8116ca Merge branch 'master' of git://estrelaeditor.git.sourceforge.net/gitroot/estrelaeditor/estrelaeditor 2012-01-18 10:19:20 -08:00
crazybutcher
73dc7ca2ed Merge remote-tracking branch 'zbstudio/master' 2012-01-18 18:54:52 +01:00
crazybutcher
8c6e111e13 updated lua to 5.1.4 2012-01-18 18:54:22 +01:00
Paul Kulchenko
305cafbfcf Added About page for zbstudio 2012-01-17 20:38:02 -08:00
Paul Kulchenko
8c3d927820 Fixed typos in the About page 2012-01-17 19:45:13 -08:00
Paul Kulchenko
b83138c127 Added version file 2012-01-17 19:44:11 -08:00
Paul Kulchenko
e7a789e466 Moved 'Watch Window' to 'View' menu for consistency and changed to always enable; disabled 'Compile' menu while debugging 2012-01-17 12:51:35 -08:00
Paul Kulchenko
d5f448c952 Updated settings to allow each window to set its default size avoid one-size-fits-all default 2012-01-17 12:35:58 -08:00
Paul Kulchenko
f43babc491 Disabled autotabs/usetabs by default in zbstudio 2012-01-16 22:34:30 -08:00
Paul Kulchenko
6a78042869 Removed duplicate call 2012-01-16 22:33:50 -08:00
Paul Kulchenko
4984cf7a4b Added ability to attach to a debugger from an arbitrary process running MobDebug; upgraded to MobDebug v0.43 2012-01-16 15:28:53 -08:00
Paul Kulchenko
6693a6cd96 Added 'pid' text 2012-01-16 14:13:57 -08:00
Paul Kulchenko
2909eeb0c3 Fixed reference to projpanel to use a local variable as the global is not guaranteed to be correct in the calling context 2012-01-16 14:13:13 -08:00
Paul Kulchenko
61260f6e48 Added reporting of the folder in which the external program is run 2012-01-16 13:08:27 -08:00
Paul Kulchenko
c741d35c67 Updated local/remote shell to handle expressions ('1+2'), accept '=' to show values, and remove 'return ' from error messages where needed 2012-01-16 11:13:45 -08:00
Paul Kulchenko
18e06631bf Fixed an issue with saving a new file when project filetree is open 2012-01-15 19:18:24 -08:00
Paul Kulchenko
efd78f57b9 Fixed issue with autocomplete that caused an error when a substring of an earlier word is typed 2012-01-15 19:09:36 -08:00
Paul Kulchenko
e366377d64 Added display of nil values for variables in the shell (local and remote) 2012-01-15 15:26:43 -08:00
Paul Kulchenko
4b334a0d40 Updated spec list for zbstudio to limit specs to lua 2012-01-15 13:32:11 -08:00
Paul Kulchenko
c3471d0077 Added logic to unhide wx window while debugging or running wxwidget application 2012-01-15 10:47:58 -08:00
Paul Kulchenko
7c7a45d99d Fix to make display of errors with and without stack trace consistent in the shellbox/console 2012-01-14 23:53:00 -08:00
Paul Kulchenko
c57215aeeb Fixed a bug in shell that prevented some of the errors from being displayed 2012-01-14 23:27:09 -08:00
Paul Kulchenko
66e0e04f45 Fixed filetree selection when 'untitled' window is active 2012-01-14 23:21:02 -08:00
Paul Kulchenko
9d1d3256c8 Fixed project browse dialog when no editor window is open 2012-01-14 23:10:42 -08:00
Paul Kulchenko
d61a0d64fc Added manifest for zbstudio 2012-01-12 23:16:02 -08:00
Paul Kulchenko
796e793902 Fixed fields left from the replaced shellbox panel 2012-01-12 23:15:32 -08:00
Paul Kulchenko
adfc4d98a7 Made default windows larger for the first run 2012-01-11 21:54:27 -08:00
Paul Kulchenko
cb28bb1b97 Fixed hiding 'load style' menu for zbstudio 2012-01-10 23:44:28 -08:00
Paul Kulchenko
77ae45ef8b Disabled maximized buttons for output/console and project windows as those are not useful and don't work correctly in all cases 2012-01-10 23:43:31 -08:00
Paul Kulchenko
d64b44943b Renamed 'View' menu items 2012-01-10 23:42:26 -08:00
Paul Kulchenko
8fb808d75f Added winapi module to be able to (optionally) show wx windows under running/debugging 2012-01-10 23:25:49 -08:00
crazybutcher
81e92eec88 changed defaults a bit, disabled autocomplete dynword engine by default 2012-01-08 14:47:21 +01:00
crazybutcher
7d763054b7 improved dynamic word ac engine (counts words active and handles delete/insert ops) 2012-01-08 14:45:38 +01:00
crazybutcher
6b39babf34 bugfix nblayout loader: assure openDocuments[id].index is correct 2012-01-08 14:44:45 +01:00
crazybutcher
214c598a85 added rudimentary notebook layout saving (cannot cope with complex splits yet) 2012-01-07 23:06:35 +01:00
crazybutcher
a297104017 bugfix in filetree for "save path" due to ui restructure 2012-01-07 23:05:36 +01:00
crazybutcher
f6e72fc9ce shell execute: prefer direct string over "return" version 2012-01-06 23:40:24 +01:00
crazybutcher
631ca23a97 main frame now managed through wxAUI, more customizeable layout 2012-01-06 23:25:00 +01:00
crazybutcher
c2d9a0dbac Merge remote branch 'zbstudio/master'
Conflicts:
	src/editor/shellbox.lua
2012-01-06 19:49:13 +01:00
Paul Kulchenko
cec4eb869d Merge branch 'simplified-shellbox' 2012-01-06 09:36:49 -08:00
crazybutcher
7602facb7a Merge remote branch 'zbstudio/master' 2012-01-06 18:32:49 +01:00
crazybutcher
d5827e233c bugfix for luxinia interpreters (do not prepend directory for exe)
bugfix when creating an error in the shell
2012-01-06 14:26:33 +01:00
crazybutcher
d59a92e0bf bugfix in filetree and loadfile when starting from empty sessions 2012-01-06 13:51:55 +01:00
crazybutcher
65d460452b luxinia interpreters should only load when found on system 2012-01-06 09:37:43 +01:00
Paul Kulchenko
867de8f3e4 Fixed localization of 'next' variable, which was causing debugger failure 2012-01-05 23:11:49 -08:00
crazybutcher
ec756721c2 bring back stack traceback on shell execute but filter traces 2012-01-06 00:04:15 +01:00
crazybutcher
3b554526c6 bugfix with file execution in shell 2012-01-05 19:03:16 +01:00
Paul Kulchenko
4246d7683a Updated resources for zbstudio with a new logo 2012-01-04 22:32:20 -08:00
Paul Kulchenko
b7c922e253 Updated prompt symbol in the shell; redirected local shell output back to the shell window 2012-01-04 19:08:09 -08:00
Paul Kulchenko
beaeb9a65d Updated icon license to MIT license and added permission reference 2012-01-04 14:55:34 -08:00
Paul Kulchenko
b3d0f40519 Redirected all shell output (print and such) to the output window 2012-01-04 14:07:24 -08:00
Paul Kulchenko
c64906d09a Added 'clear' command to the shell to clear shell window 2012-01-04 13:34:05 -08:00
Paul Kulchenko
2d993203f8 Added ability for the shell to handle async output; the output is inserted before the prompt. Fixed a bug in the debugger that wasn't redirecting the shell output to the shell 2012-01-04 13:25:50 -08:00
crazybutcher
3fdc605d36 Merge remote branch 'zbstudio/master' 2012-01-04 22:05:15 +01:00
Paul Kulchenko
393c0703a6 Added re-scanning of folders in the filetree to keep the data up-to-date. The re-scanning is done on expanding a node or on activation of a file/folder 2012-01-04 00:31:40 -08:00
Paul Kulchenko
2c396b775e Fixed loading icons when no ico file is present 2012-01-03 22:21:33 -08:00
Paul Kulchenko
d14c4b544a Updated marker for the current line in the console 2012-01-03 22:19:40 -08:00
crazybutcher
730835a04d bugfix when deleting editor tab via middlemouse, the third try ;) this time should delete proper tab and preserve current selected tab 2012-01-03 19:12:04 +01:00
crazybutcher
db315532ed Merge remote branch 'zbstudio/master'
Conflicts:
	src/editor/commands.lua
2012-01-03 18:57:09 +01:00
crazybutcher
cc9128ad73 bugfix, filename loaded multiple times, also fixes bug with selection not updated on new file loads 2012-01-03 18:52:12 +01:00
Paul Kulchenko
99763ce992 Simplified the interactive shell to use a single one-page control for everything; included history of commands and dynamic switching between local/remote shell 2012-01-03 00:21:43 -08:00
Paul Kulchenko
c735b7476d Added configuration and support for word wrap in the editor 2012-01-02 12:02:59 -08:00
Paul Kulchenko
932274fbbe Re-applied and simplified handling of editor tab close event 2012-01-01 20:16:31 -08:00
Paul Kulchenko
7fed63512d Removed Estrela references 2012-01-01 18:09:11 -08:00
Paul Kulchenko
14cf94f3bb Enabled 'Clear Output' menu by default for zbstudio 2012-01-01 18:04:32 -08:00
Paul Kulchenko
14665f57dd Added ability to break applications under debugging; upgraded to mobdebug v0.42 2011-12-30 12:17:52 -08:00
Paul Kulchenko
414f44b6f5 Merge branch 'master' of git://estrelaeditor.git.sourceforge.net/gitroot/estrelaeditor/estrelaeditor 2011-12-29 14:22:32 -08:00
Paul Kulchenko
0c1a335aa0 Moved wx.dll file to allow execution and debugging of wx applications 2011-12-29 14:22:07 -08:00
Paul Kulchenko
ae04d6e1aa Fixed logic of loading application .ico files to allow icons of different sizes to be correctly used 2011-12-29 13:16:53 -08:00
CrazyButcher
6fb6c73495 Merge remote-tracking branch 'zbstudio/master'
Conflicts:
	src/editor/gui.lua
2011-12-29 16:51:48 +01:00
CrazyButcher
5083d561d2 bugfix with middle mouse close file tab 2011-12-29 16:00:45 +01:00
CrazyButcher
2a2bfa69a2 autcomplete bugfix for non-lua specs 2011-12-29 13:39:48 +01:00
CrazyButcher
56f05aa5fe luxinia1 api loading bugfix 2011-12-29 13:02:15 +01:00
Paul Kulchenko
4607721020 Moved wx.dll file to allow debugging of wx applications 2011-12-27 18:28:40 -08:00
Paul Kulchenko
329baf4b82 Added killing a debugger client on exit from IDE 2011-12-27 18:26:31 -08:00
Paul Kulchenko
ed30c2399d Fixed an issue with the filetree when a new file is saved 2011-12-27 08:32:09 -08:00
Paul Kulchenko
7663cbbf0c Removed slash conversion in debugger as it is no longer needed with mobdebug v0.41. Normalized use of slashes in file names 2011-12-24 18:58:06 -08:00
Paul Kulchenko
c48182b902 Added logic to populate and expand nodes in the project filetree to correctly mark active files in subfolders.
Removed code to delete and repopulate tree nodes as this logic was recreating all tree objects (which made them lost their content, marks, open/close state and everything else). This change makes the list (potentially) stale if the directory content changes, but this issue will be addressed later.
2011-12-23 19:01:12 -08:00
Paul Kulchenko
9297a18b8d Added handling of editor tab close event to fix the issue with closing notebook tab with middle mouse button.
Added close button on an active notebook tab.
2011-12-23 18:58:51 -08:00
Paul Kulchenko
4fdeccdbc1 Removed commented out code 2011-12-23 18:46:46 -08:00
Paul Kulchenko
5c76dbabd6 Upgraded mobdebug module to v0.41 to include changes with handling path conversion 2011-12-23 13:55:08 -08:00
Paul Kulchenko
b6176efd07 Improved project filetree display
Fixed expanding empty folder; now removes expand item on it.
Fixed marking an item in subfolders; now markes those files that are open
in the editor (but only if the subfolder has been expanded).
Removed slash from folder names; simplified file/folder handling logic.
2011-12-22 21:51:34 -08:00
Paul Kulchenko
5327916817 Modified logic for 'jump to function' list to recognize 'local foo = function' and 'foo.bar = function' syntax; added default message to the function list 2011-12-22 19:32:06 -08:00
CrazyButcher
78e52ac04a bugfix for default interpreter setup 2011-12-22 18:17:21 +01:00
CrazyButcher
a9b1729057 do not put user.lua under source control 2011-12-22 18:05:46 +01:00
Paul Kulchenko
a226c6e432 Documentation clean-up: added README, updated LICENSE, moved doc/ files 2011-12-19 22:37:13 -08:00
Paul Kulchenko
79af98d75b Added marking of current file in the project file tree; disabled slash conversion in file load 2011-12-18 16:21:47 -08:00
Paul Kulchenko
ab26ded71a Tweaks to the filetree control to set the font and to better align the browse button 2011-12-18 10:43:41 -08:00
Paul Kulchenko
defba4f767 Added a new set of icons and handling of custom icons in zbstudio 2011-12-18 10:23:20 -08:00
Paul Kulchenko
585c5c0f9c Updated GetBitmap calls to reference correct client (TOOLBAR/OTHER); moved filetree.lua call to be after gui.lua to make ArtProvider.GetBitmap call to work 2011-12-18 10:18:22 -08:00
crazybutcher
047165b6aa bugfix on debugger.pid boolean behavior, clear all markers prior actions 2011-12-17 15:50:13 +01:00
Paul Kulchenko
3d0e52bdbe Added killing the debugee process for real when debugging is stopped by the user 2011-12-13 23:03:46 -08:00
Paul Kulchenko
2e1a512f00 Another end-of-line conversion to fix CRLF endings that were added by the beautification process 2011-12-12 17:01:37 -08:00
crazybutcher
09dbdc1cb1 rename Start Debugging to Continue if debugger.server is present 2011-12-12 23:40:29 +01:00
Paul Kulchenko
a9835c25cb Added Trace command to show execution path in debugger.
Added reporting of error in Watch window and fixed a bug in the Watch
window that made Trace to stop on errors in Watch expressions.
2011-12-12 13:18:17 -08:00
Paul Kulchenko
dab674be91 Split Run and Continue commands 2011-12-12 11:53:59 -08:00
Paul Kulchenko
8e5a6bc284 Returned back wx*.dll as wxLua dll don't draw folds correctly and have tendency to crash in autocomplete 2011-12-12 11:37:56 -08:00
Paul Kulchenko
fe53414868 Ran tools/ and spec/ files through a beautifier 2011-12-12 09:33:35 -08:00
Paul Kulchenko
6f675b60cb Ran files with preferences through a beautifier 2011-12-11 22:03:54 -08:00
Paul Kulchenko
85be275590 Ran most of the lua files (except tools, specs, apis, and lualibs) through a beautifier 2011-12-11 21:14:18 -08:00
crazybutcher
378fe2818e minor refactoring and speedup to modebug and debugging for luxinia2 :) 2011-12-11 15:26:15 +01:00
Paul Kulchenko
20ed88665a Fixed incorrect method name for debugging termination 2011-12-10 18:29:33 -08:00
Paul Kulchenko
31759939f2 Fixed issue with displaying errors in local shell;
Added markers to multi-line expressions
2011-12-10 18:27:58 -08:00
Paul Kulchenko
03b63b491e Updated icon in the executable 2011-12-10 16:55:07 -08:00
Paul Kulchenko
409f1f4214 Enabled singleinstance for zbstudio to check that only one instance is running 2011-12-10 16:54:43 -08:00
Paul Kulchenko
caf9db40b1 Fixed method name in the debugger 2011-12-10 15:12:41 -08:00
Paul Kulchenko
fc7e075a01 Added back all zbstudio files that got removed in the merge 2011-12-10 15:11:44 -08:00
crazybutcher
c956350dc2 minor changes to allow interpreter controlled debugging 2011-12-10 15:36:40 +01:00
crazybutcher
8273b622e9 added missing doc info about app.preinit 2011-12-10 15:04:56 +01:00
crazybutcher
85b016457b sync with zbstudio issue 2011-12-10 14:55:22 +01:00
crazybutcher
15154050f9 Merge remote branch 'zbstudio/master'
Conflicts:
	cfg/config.lua
	doc/defs.lua
	estrela/config.lua
	src/editor/commands.lua
	src/editor/debugger.lua
	src/editor/filetree.lua
	src/editor/gui.lua
	src/editor/menu_file.lua
	src/editor/menu_project.lua
	src/editor/menu_tools.lua
	src/editor/menu_view.lua
	src/editor/output.lua
	src/editor/shellbox.lua
	src/editor/style.lua
	src/main.lua
2011-12-10 14:53:08 +01:00
Paul Kulchenko
d6472a2fd5 Switched from wxNotebook to wxAuiNotebook as it has better looking UI 2011-12-09 23:08:00 -08:00
Paul Kulchenko
3d452e3092 Updated wx dlls to use ones from http://code.google.com/p/luaforwindows/, which have smaller size 2011-12-09 22:59:40 -08:00
Paul Kulchenko
bc2a15915c Added missing config for one of the applications 2011-12-09 21:45:07 -08:00
crazybutcher
6cdecea47c moving default config to application path, and changed config load order:
1) internal defaults
2) app/config.lua
3) cfg/user.lua
4) commandline -cfg

Conflicts:

	src/main.lua
2011-12-09 21:41:05 -08:00
crazybutcher
4967a0a68b removed dead meat 2011-12-09 21:35:05 -08:00
Paul Kulchenko
2428b66add Refactored and normalized interfaces to use Debugger*, Project*, FileTree* convention for public methods; updated local methods in debugger 2011-12-09 21:33:10 -08:00
Paul Kulchenko
0a550c1d25 Convert CRLF that were inherited with original clone to LF 2011-12-07 20:20:22 -08:00
crazybutcher
43e0566cb6 DebuggerFileAction should return true on success 2011-12-07 21:41:07 +01:00
crazybutcher
8739e37faa improve async debugger behavior 2011-12-07 21:31:12 +01:00
crazybutcher
fcc11f7dff moving default config to application path, and changed config load order:
1) internal defaults
2) app/config.lua
3) cfg/user.lua
4) commandline -cfg
2011-12-07 21:10:21 +01:00
crazybutcher
705b5f939c removed dead meat 2011-12-07 19:17:34 +01:00
Paul Kulchenko
af27ef7682 Refactored debugger commands to match debugserver interface in defs.lua 2011-12-07 09:38:26 -08:00
Paul Kulchenko
863f2780b3 Refactored interpreter/debugger interface to move the logic into the interpreter 2011-12-06 22:46:14 -08:00
Paul Kulchenko
790191a681 Added handling of .hasdebugger attribute 2011-12-06 22:38:25 -08:00
Paul Kulchenko
ca0fda0bee Fixed using projectdir from interpreter with debugger 2011-12-06 19:20:22 -08:00
Paul Kulchenko
81e4048754 Added 'Start debugger server' menu; updated starting debugger server automatically to be application-based 2011-12-06 17:53:45 -08:00
Paul Kulchenko
353336796d Fixed an issue with LoadStyle dialog and style processing 2011-12-06 15:30:55 -08:00
Paul Kulchenko
c39ee8fb2f Fixed issue with closing an editor window and then canceling Save dialog 2011-12-06 15:16:07 -08:00
Paul Kulchenko
fbcc555f4e Fixed issue with running/debugging an 'untitled' file 2011-12-06 15:15:37 -08:00
Paul Kulchenko
43237b1b1d Added logic to remove menu items not used in zbstudio 2011-12-06 09:15:53 -08:00
Paul Kulchenko
5f8ee5ce63 Added 'Lua with debugger' interpreter and reverted changes to 'Lua' interpreter back;
Registered 'Lua with debugger' with zbstudio by default;
Added logic to load custom icons
2011-12-05 12:16:32 -08:00
crazybutcher
edd82b8a4a Fix CRLF 2011-12-05 20:21:43 +01:00
Paul Kulchenko
d710fdb4a9 Added preinit callback; moved postinit before frame:Show 2011-12-04 23:43:59 -08:00
Paul Kulchenko
b7124a26ba Fixed shortcuts in Project menu 2011-12-04 23:28:40 -08:00
Paul Kulchenko
fba27ba1b0 Added logic to only enable Tools menu if it is not empty 2011-12-04 16:47:28 -08:00
crazybutcher
1a2a3ac721 abstract debugger interface (untested) 2011-12-04 20:54:30 +01:00
135 changed files with 26695 additions and 17999 deletions

View File

@@ -1,160 +1,199 @@
Estrela Editor License
=============================================================================
Estrela Editor sources are released under the MIT License
Copyright (c) 2008-2011
Luxinia DevTeam:
Eike Decker & Christoph Kubisch
info at luxinia.de
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
wxLua License
=============================================================================
http://wxlua.sourceforge.net/
Pre-Built binaries for wxLua/WxWindows
Original wxLua Lua sample IDE:
Lomtick Software
J. Winwood & John Labenski
luascript at thersgb.net
wxLua is based on
wxWindows Library Licence, Version 3
Copyright (c) 1998 Julian Smart, Robert Roebling et al
Everyone is permitted to copy and distribute verbatim copies
of this licence document, but changing it is not allowed.
WXWINDOWS LIBRARY LICENCE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
This library is free software; you can redistribute it and/or modify it
under the terms of the GNU Library General Public Licence as published by
the Free Software Foundation; either version 2 of the Licence, or (at
your option) any later version.
This library is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library
General Public Licence for more details.
You should have received a copy of the GNU Library General Public Licence
along with this software, usually in a file named COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA.
EXCEPTION NOTICE
1. As a special exception, the copyright holders of this library give
permission for additional uses of the text contained in this release of
the library as licenced under the wxWindows Library Licence, applying
either version 3 of the Licence, or (at your option) any later version of
the Licence as published by the copyright holders of version 3 of the
Licence document.
2. The exception is that you may use, copy, link, modify and distribute
under the user's own terms, binary object code versions of works based
on the Library.
3. If you copy code from files distributed under the terms of the GNU
General Public Licence or the GNU Library General Public Licence into a
copy of this library, as this licence permits, the exception does not
apply to the code that you add in this way. To avoid misleading anyone as
to the status of such modified files, you must delete this exception
notice from such code and/or adjust the licensing conditions notice
accordingly.
4. If you write modifications of your own for this library, it is your
choice whether to permit this exception to apply to your modifications.
If you do not wish that, you must delete the exception notice from such
code and/or adjust the licensing conditions notice accordingly.
Lua License
=============================================================================
Copyright: © 1994-2006 Lua.org, PUC-Rio.
Homepage: http://www.lua.org
License: http://www.lua.org/copyright.html
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
LuaFileSystem
=============================================================================
LuaFileSystem was designed by Roberto Ierusalimschy, André Carregal and Tomás
Guisasola as part of the Kepler Project, which holds its copyright.
Homepage: http://www.keplerproject.org/luafilesystem/index.html
License: http://www.keplerproject.org/luafilesystem/license.html
=============================================================================
LuaSockets
=============================================================================
Copyright: © 2004-2006 Diego Nehab. All rights reserved.
Homepage: http://www.cs.princeton.edu/~diego/professional/luasocket/
License: http://www.lua.org/copyright.html (same as LUA)
=============================================================================
ZMQ
=============================================================================
Copyright: © 2007-2011 iMatix Corporation and Contributors
Homepage: http://www.zeromq.org/
License: http://www.zeromq.org/area:licensing
LuaZMQ
Copyright: © 2011 by Robert G. Jakabosky
Homepage: https://github.com/Neopallium/lua-zmq
=============================================================================
MojoShader
=============================================================================
Copyright: © 2008-2010 Ryan C. Gordon
Homepage: http://icculus.org/mojoshader/
License: http://hg.icculus.org/icculus/mojoshader/raw-file/tip/LICENSE.txt
=============================================================================
CLCC
=============================================================================
Copyright: © 2009 Organic Vectory B.V.
Homepage: http://clcc.sourceforge.net/
License: boost
CLCC was modified by Christoph Kubisch to support multiple platforms and
output file generation.
=============================================================================
--[[ ZeroBrane Studio License ]]-------------------------------------------
ZeroBrane Studio sources are released under the MIT License
Copyright (c) 2011-2012 Paul Kulchenko (paul@kulchenko.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
--[[ Estrela Editor License ]]---------------------------------------------
Estrela Editor sources are released under the MIT License
Copyright (c) 2008-2012
Luxinia DevTeam:
Christoph Kubisch & Eike Decker
info at luxinia.de
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
--[[ wxLua License License ]]----------------------------------------------
http://wxlua.sourceforge.net/
Pre-Built binaries for wxLua/WxWindows
Original wxLua Lua sample IDE:
Lomtick Software
J. Winwood & John Labenski
luascript at thersgb.net
wxLua is based on
wxWindows Library Licence, Version 3
Copyright (c) 1998 Julian Smart, Robert Roebling et al
Everyone is permitted to copy and distribute verbatim copies
of this licence document, but changing it is not allowed.
WXWINDOWS LIBRARY LICENCE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
This library is free software; you can redistribute it and/or modify it
under the terms of the GNU Library General Public Licence as published by
the Free Software Foundation; either version 2 of the Licence, or (at
your option) any later version.
This library is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library
General Public Licence for more details.
You should have received a copy of the GNU Library General Public Licence
along with this software, usually in a file named COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA.
EXCEPTION NOTICE
1. As a special exception, the copyright holders of this library give
permission for additional uses of the text contained in this release of
the library as licenced under the wxWindows Library Licence, applying
either version 3 of the Licence, or (at your option) any later version of
the Licence as published by the copyright holders of version 3 of the
Licence document.
2. The exception is that you may use, copy, link, modify and distribute
under the user's own terms, binary object code versions of works based
on the Library.
3. If you copy code from files distributed under the terms of the GNU
General Public Licence or the GNU Library General Public Licence into a
copy of this library, as this licence permits, the exception does not
apply to the code that you add in this way. To avoid misleading anyone as
to the status of such modified files, you must delete this exception
notice from such code and/or adjust the licensing conditions notice
accordingly.
4. If you write modifications of your own for this library, it is your
choice whether to permit this exception to apply to your modifications.
If you do not wish that, you must delete the exception notice from such
code and/or adjust the licensing conditions notice accordingly.
--[[ Lua License ]]--------------------------------------------------------
Copyright: © 1994-2006 Lua.org, PUC-Rio.
Homepage: http://www.lua.org
License: http://www.lua.org/copyright.html
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
--[[ LuaFileSystem License ]]----------------------------------------------
LuaFileSystem was designed by Roberto Ierusalimschy, André Carregal and Tomás
Guisasola as part of the Kepler Project, which holds its copyright.
Homepage: http://www.keplerproject.org/luafilesystem/index.html
License: http://www.keplerproject.org/luafilesystem/license.html
--[[ LuaSockets License ]]-------------------------------------------------
Copyright: © 2004-2006 Diego Nehab. All rights reserved.
Homepage: http://www.cs.princeton.edu/~diego/professional/luasocket/
License: http://www.lua.org/copyright.html (same as LUA)
--[[ ZMQ License ]]--------------------------------------------------------
Copyright: © 2007-2011 iMatix Corporation and Contributors
Homepage: http://www.zeromq.org/
License: http://www.zeromq.org/area:licensing
LuaZMQ
Copyright: © 2011 by Robert G. Jakabosky
Homepage: https://github.com/Neopallium/lua-zmq
--[[ MojoShader License ]]-------------------------------------------------
Copyright: © 2008-2010 Ryan C. Gordon
Homepage: http://icculus.org/mojoshader/
License: http://hg.icculus.org/icculus/mojoshader/raw-file/tip/LICENSE.txt
--[[ CLCC License ]]-------------------------------------------------------
Copyright: © 2009 Organic Vectory B.V.
Homepage: http://clcc.sourceforge.net/
License: boost
CLCC was modified by Christoph Kubisch to support multiple platforms and
output file generation.
--[[ MobDebug License ]]---------------------------------------------------
MobDebug sources are released under the MIT License
Copyright (c) 2011 Paul Kulchenko (paul@kulchenko.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

63
README Normal file
View File

@@ -0,0 +1,63 @@
A simple and extensible Lua IDE and debugger. It supports multiple file
formats, "api" for autocompletion and tooltips, and custom command-line
tools. Its main focus is extensibility for target applications using Lua.
--[[ FEATURES ]]-----------------------------------------------------------
* Written in Lua, so easily customizable
* Automatically loads several 'plugin' like classes
- applications: overall control of applications settings
- specs (spec/): file syntax, lexer, keywords
- apis (api/): for code-completion and tool-tips
- interpreters (interpreters/): how a project is run
- config (cfg/): contains style and basic editor settings
- tools (tools/): additional tools, e.g. cg compiler, dx fxc compiler
* Auto-completion for functions, keywords...
* Function tips
* Function list in file (quick jump to)
* Function call highlighting
* Bracket matching/highlighting
* Project file browser
* Experimental type/class guessing for auto-completion
* Support for different editor styles
* Console to directly test code snippets with local and remote execution
* Integrated debugger (with support for local and remote debugging)
--[[ FRONT-ENDS ]]--------------------------------------------------------
There is currently two front-ends using the same editor engine. The original
is "estrela", which has a focus on 3d graphics related usage of Lua, especially
in combination with the luxinia engine or luxinia2 framework.
The second is "zbstudio" which has a focus on remote use of Lua in robotics.
Both are part of the standard distribution.
--[[ INSTALLATION ]]-------------------------------------------------------
git clone git://github.com/pkulchenko/ZeroBraneStudio.git zbstudio
or
git clone git://estrelaeditor.git.sourceforge.net/gitroot/estrelaeditor/estrelaeditor estrelaeditor
--[[ USAGE ]]--------------------------------------------------------------
Open File(s):
<exe> <filename> [<filename>...]
any non-option will be treated as filename
Overriding Config:
<exe> [...] -cfg "<luacode overriding config>" [...]
e.g.: zbstudio.exe -cfg "singleinstance=false;" somefile.lua
--[[ AUTHOR ]]-------------------------------------------------------------
Estrela Editor
Luxinia Dev: Christoph Kubisch (crazybutcher@luxinia.de)
ZeroBrane Studio and MobDebug
ZeroBrane LLC: Paul Kulchenko (paul@kulchenko.com)
--[[ LICENSE ]]------------------------------------------------------------
See LICENSE file

View File

@@ -1,205 +1,205 @@
-- authors: Luxinia Dev (Eike Decker & Christoph Kubisch)
---------------------------------------------------------
local function fn (description)
local description2,returns,args = description:match("(.+)%-%s*(%b())%s*(%b())")
if not description2 then
return {type="function",description=description,
returns="(?)"}
end
return {type="function",description=description2,
returns=returns:gsub("^%s+",""):gsub("%s+$",""), args = args}
end
local function val (description)
return {type="value",description = description}
end
-- docs
local api = {
abs = fn "returns absolute value of scalars and vectors. - (typeN)(typeN)",
acos = fn "returns arccosine of scalars and vectors. - (typeN)(typeN)",
all = fn "returns true if a boolean scalar or all components of a boolean vector are true. - (bool)(boolN)",
any = fn "returns true if a boolean scalar or any component of a boolean vector is true. - (bool)(boolN)",
asin = fn "returns arcsine of scalars and vectors. - (typeN)(typeN)",
atan = fn "returns arctangent of scalars and vectors. - (typeN)(typeN)",
atan2 = fn "returns the arctangent of y/x. atan2 is well defined for every point other than the origin, even if x equals 0 and y does not equal 0. - (typeN)(typeN y, typeN x)",
ceil = fn "returns smallest integer not less than a scalar or each vector component. - (typeN)(typeN)",
clamp = fn "returns x clamped to the range [a,b]. - (typeN)(typeN x, a, b)",
clip = fn "conditionally (<0) kill a pixel before output. - ()(typeN)",
cos = fn "returns cosine of scalars and vectors. - (typeN)(typeN)",
cosh = fn "returns hyperbolic cosine of scalars and vectors. - (typeN)(typeN)",
cross = fn "returns the cross product of two three-component vectors. - (type3)(type3 a, b)",
ddx = fn "returns approximate partial derivative with respect to window-space X. - (typeN)(typeN)",
ddy = fn "returns approximate partial derivative with respect to window-space Y. - (typeN)(typeN)",
degrees = fn "converts values of scalars and vectors from radians to degrees. - (typeN)(typeN)",
determinant = fn "returns the scalar determinant of a square matrix. - (float)(floatNxN)",
distance = fn "return the Euclidean distance between two points. - (typeN)(typeN a, b)",
dot = fn "returns the scalar dot product of two vectors. - (type)(typeN a, b)",
exp = fn "returns the base-e exponential of scalars and vectors. - (typeN)(typeN)",
exp2 = fn "returns the base-2 exponential of scalars and vectors. - (typeN)(typeN)",
faceforward = fn "returns a normal as-is if a vertex's eye-space position vector points in the opposite direction of a geometric normal, otherwise return the negated version of the normal. - (typeN)(typeN Nperturbated, Incident, Ngeometric)",
floatToIntBits = fn "returns the 32-bit integer representation of an IEEE 754 floating-point scalar or vector - (intN)(floatN)",
floatToRawIntBits = fn "returns the raw 32-bit integer representation of an IEEE 754 floating-point scalar or vector. - (intN)(floatN)",
floor = fn "returns largest integer not greater than a scalar or each vector component. - (typeN)(typeN)",
fmod = fn "returns the remainder of x/y with the same sign as x. - (typeN)(typeN x, y)",
frac = fn "returns the fractional portion of a scalar or each vector component. - (typeN)(typeN)",
frexp = fn "splits scalars and vectors into normalized fraction and a power of 2. - (typeN)(typeN x, out typeN e)",
fwidth = fn "returns sum of approximate window-space partial derivatives magnitudes. - (typeN)(typeN)",
intBitsToFloat = fn "returns the float value corresponding to a given bit represention.of a scalar int value or vector of int values. - (floatN)(intN)",
isfinite = fn "test whether or not a scalar or each vector component is a finite value. - (boolN)(typeN)",
isinf = fn "test whether or not a scalar or each vector component is infinite. - (boolN)(typeN)",
isnan = fn "test whether or not a scalar or each vector component is not-a-number. - (boolN)(typeN)",
ldexp = fn "returns x times 2 rained to n. - (typeN)(typeN a, n)",
length = fn "return scalar Euclidean length of a vector. - (type)(typeN)",
lerp = fn "lerp - returns linear interpolation of two scalars or vectors based on a weight. - (typeN)(typeN a, b, weight)",
lit = fn "computes lighting coefficients for ambient(x), diffuse(y), and specular(z) lighting contributions (w=1). - (type4)(type NdotL, NdotH, specshiny)",
log = fn "returns the natural logarithm of scalars and vectors. - (typeN)(typeN)",
log10 = fn "returns the base-10 logarithm of scalars and vectors. - (typeN)(typeN)",
log2 = fn "returns the base-2 logarithm of scalars and vectors. - (typeN)(typeN)",
max = fn "returns the maximum of two scalars or each respective component of two vectors. - (typeN)(typeN a, b)",
min = fn "returns the minimum of two scalars or each respective component of two vectors. - (typeN)(typeN a, b)",
mul = fn "Returns the vector result of multiplying a matrix M by a column vector v; a row vector v by a matrix M; or a matrix A by a second matrix B. - (typeN)(typeNxN/typeN a, typeN/typeNxN b)",
normalize = fn "Returns the normalized version of a vector, meaning a vector in the same direction as the original vector but with a Euclidean length of one. - (typeN)(typeN)",
pow = fn "returns x to the y-th power of scalars and vectors. - (typeN)(typeN x, y)",
radians = fn "converts values of scalars and vectors from degrees to radians. - (typeN)(typeN)",
reflect = fn "returns the reflectiton vector given an incidence vector and a normal vector. - (typeN)(typeN incidence, normal)",
refract = fn "computes a refraction vector. - (typeN)(typeN incidence, normal, type eta)",
round = fn "returns the rounded value of scalars or vectors. - (typeN)(typeN a)",
rsqrt = fn "returns reciprocal square root of scalars and vectors. 1/sqrt. - (typeN)(typeN)",
saturate = fn "returns x saturated to the range [0,1]. - (typeN)(typeN)",
sign = fn "returns sign (1 or -1) of scalar or each vector component. - (typeN)(typeN)",
sin = fn "returns sine of scalars and vectors. - (typeN)(typeN)",
sincos = fn "returns sine of scalars and vectors. - ()(typeN x, out typeN sin, out typeN cos)",
sinh = fn "returns hyperbolic sine of scalars and vectors. - (typeN)(typeN)",
sqrt = fn "returns square root of scalars and vectors. - (typeN)(typeN)",
step = fn "implement a step function returning either zero or one (a <= b). - (typeN)(typeN a, b)",
tan = fn "returns tangent of scalars and vectors. - (typeN)(typeN)",
tanh = fn "returns hyperbolic tangent of scalars and vectors. - (typeN)(typeN)",
transpose = fn "returns transpose matrix of a matrix. - (typeRxC)(typeCxR)",
trunc = fn "returns largest integer not greater than a scalar or each vector component. - (typeN)(typeN)",
tex1D = fn "performs a texture lookup in a given 1D sampler and, in some cases, a shadow comparison (as .y coord). May also use pre computed derivatives if those are provided. Texeloffset only in gp4 or higher profiles. - (float4)(sampler1D, float/float2 s, |float dx, dy|,[int texeloffset])",
tex1Dbias = fn "performs a texture lookup with bias in a given sampler (as .w). - (float4)(sampler1D, float4 s, [int texeloffset])",
tex1Dcmpbias = fn "performs a texture lookup with bias and shadow compare in a given sampler (compare as .y, bias as .w). - (float4)(sampler1D, float4 s, [int texeloffset])",
tex1Dcmplod = fn "performs a texture lookup with a specified level of detail and a shadow compare in a given sampler (compare as .y, lod as .w). - (float4)(sampler1D, float4 s, [int texeloffset])",
tex1Dfetch = fn "performs an unfiltered texture lookup in a given sampler (lod as .w). - (float4)(sampler1D, int4 s, [int texeloffset])",
tex1Dlod = fn "performs a texture lookup with a specified level of detail in a given sampler (lod as .w) - (float4)(sampler1D, float4 s, [int texeloffset])",
tex1Dproj = fn "performs a texture lookup with projection in a given sampler. May perform a shadow comparison if argument for shadow comparison is provided. (shadow in .y for float3 coord, proj in .y or .z) - (float4)(sampler1D, float2/float3 s, [int texeloff])",
tex1Dsize = fn "returns the size of a given texture image for a given level of detail. (only gp4 profiles) - (int3)(sampler1D, int lod)",
tex2D = fn "performs a texture lookup in a given 2D sampler and, in some cases, a shadow comparison (as .z coord). May also use pre computed derivatives if those are provided. Texeloffset only in gp4 or higher profiles. - (float4)(sampler2D, float2/float3 s, |float2 dx, dy|,[int texeloffset])",
tex2Dbias = fn "performs a texture lookup with bias in a given sampler (as .w). - (float4)(sampler2D, float4 s, [int texeloffset])",
tex2Dcmpbias = fn "performs a texture lookup with bias and shadow compare in a given sampler (compare as .z, bias as .w). - (float4)(sampler2D, float4 s, [int texeloffset])",
tex2Dcmplod = fn "performs a texture lookup with a specified level of detail and a shadow compare in a given sampler (compare as .y, lod as .w). - (float4)(sampler2D, float4 s, [int texeloffset])",
tex2Dfetch = fn "performs an unfiltered texture lookup in a given sampler (lod as .w). - (float4)(sampler2D, int4 s, [int texeloffset])",
tex2Dlod = fn "performs a texture lookup with a specified level of detail in a given sampler (lod as .w) - (float4)(sampler2D, float4 s, [int texeloffset])",
tex2Dproj = fn "performs a texture lookup with projection in a given sampler. May perform a shadow comparison if argument for shadow comparison is provided. (shadow in .z for float3 coord, proj in .z or .w) - (float4)(sampler2D, float3/float4 s, [int texeloff])",
tex2Dsize = fn "returns the size of a given texture image for a given level of detail. (only gp4 profiles) - (int3)(sampler2D, int lod)",
tex2Dgather = fn "returns 4 texels of a given single channel texture image for a given level of detail. (only gp4 profiles) - (int3)(sampler2D, int lod)",
tex3D = fn "performs a texture lookup in a given 3D sampler. May also use pre computed derivatives if those are provided. Texeloffset only in gp4 or higher profiles. - (float4)(sampler3D, float3 s, {float3 dx, dy},[int texeloffset])",
tex3Dbias = fn "performs a texture lookup with bias in a given sampler (as .w). - (float4)(sampler3D, float4 s, [int texeloffset])",
tex3Dfetch = fn "performs an unfiltered texture lookup in a given sampler (lod as .w). - (float4)(sampler3D, int4 s, [int texeloffset])",
tex3Dlod = fn "performs a texture lookup with a specified level of detail in a given sampler (lod as .w) - (float4)(sampler3D, float4 s, [int texeloffset])",
tex3Dproj = fn "performs a texture lookup with projection in a given sampler. (proj in .w) - (float4)(sampler3D, float4 s, [int texeloff])",
tex3Dsize = fn "returns the size of a given texture image for a given level of detail. (only gp4 profiles) - (int3)(sampler3D, int lod)",
texBUF = fn "performs an unfiltered texture lookup in a given texture buffer sampler. (only gp4 profiles) - (float4)(samplerBUF, int s)",
texBUFsize = fn "returns the size of a given texture image for a given level of detail. (only gp4 profiles) - (int3)(samplerBUF, int lod)",
texRBUF = fn "performs a multi-sampled texture lookup in a renderbuffer. (only gp4 profiles) - (float4)(samplerRBUF, int2 s, int sample)",
texRBUFsize = fn "returns the size of a given renderbuffer. (only gp4 profiles) - (int2)(samplerBUF)",
texCUBE = fn "performs a texture lookup in a given CUBE sampler and, in some cases, a shadow comparison (float4 coord). May also use pre computed derivatives if those are provided. Texeloffset only in gp4 or higher profiles. - (float4)(samplerCUBE, float3/float4 s, |float3 dx, dy|)",
texCUBEbias = fn "performs a texture lookup with bias in a given sampler (as .w). - (float4)(sampler1D, float4 s, [int texeloffset])",
texCUBElod = fn "performs a texture lookup with a specified level of detail in a given sampler (lod as .w) - (float4)(sampler1D, float4 s, [int texeloffset])",
texCUBEproj = fn "performs a texture lookup with projection in a given sampler. (proj in .w) - (float4)(samplerCUBE, float4 s)",
texCUBEsize = fn "returns the size of a given texture image for a given level of detail. (only gp4 profiles) - (int3)(sampler1D, int lod)",
texRECT = fn "performs a texture lookup in a given RECT sampler and, in some cases, a shadow comparison (as .z). May also use pre computed derivatives if those are provided. Texeloffset only in gp4 or higher profiles. - (float4)(samplerRECT, float2/float3 s, |float2 dx, dy|, [int texeloff])",
texRECTbias = fn "performs a texture lookup with bias in a given sampler (as .w). - (float4)(samplerRECT, float4 s, [int texeloffset])",
texRECTfetch = fn "performs an unfiltered texture lookup in a given sampler (lod as .w). - (float4)(samplerRECT, int4 s, [int texeloffset])",
texRECTlod = fn "performs a texture lookup with a specified level of detail in a given sampler (lod as .w) - (float4)(samplerRECT, float4 s, [int texeloffset])",
texRECTproj = fn "performs a texture lookup with projection in a given sampler. May perform a shadow comparison if argument for shadow comparison is provided. (shadow in .z for float3 coord, proj in .z or .w) - (float4)(samplerRECT, float3/float4 s, [int texeloff])",
texRECTsize = fn "returns the size of a given texture image for a given level of detail. (only gp4 profiles) - (int3)(samplerRECT, int lod)",
tex1DARRAY = fn "performs a texture lookup in a given 1D sampler array and, in some cases, a shadow comparison (as .z). May also use pre computed derivatives if those are provided. Texeloffset only in gp4 or higher profiles. - (float4)(sampler1DARRAY, float2/float3 s, {float dx, dy},[int texeloffset])",
tex1DARRAYbias = fn "performs a texture lookup with bias in a given sampler (as .w). - (float4)(sampler1DARRAY, float4 s, [int texeloffset])",
tex1DARRAYcmpbias = fn "performs a texture lookup with bias and shadow compare in a given sampler (layer as .y, compare as .z, bias as .w). - (float4)(sampler1DARRAY, float4 s, [int texeloffset])",
tex1DARRAYcmplod = fn "performs a texture lookup with a specified level of detail and a shadow compare in a given sampler (compare as .z, lod as .w). - (float4)(sampler1DARRAY, float4 s, [int texeloffset])",
tex1DARRAYfetch = fn "performs an unfiltered texture lookup in a given sampler (lod as .z). - (float4)(sampler1DARRAY, int3 s, [int texeloffset])",
tex1DARRAYlod = fn "performs a texture lookup with a specified level of detail in a given sampler (lod as .z) - (float4)(sampler1DARRAY, float3 s, [int texeloffset])",
tex1DARRAYproj = fn "performs a texture lookup with projection in a given sampler. May perform a shadow comparison if argument for shadow comparison is provided. (shadow in .z for float3 coord, proj in .z or .w) - (float4)(sampler1DARRAY, float3/float4 s, [int texeloff])",
tex1DARRAYsize = fn "returns the size of a given texture image for a given level of detail. (only gp4 profiles) - (int3)(sampler1DARRAY, int lod)",
tex2DARRAY = fn "performs a texture lookup in a given 2D sampler array and, in some cases, a shadow comparison (as .w coord). May also use pre computed derivatives if those are provided. Texeloffset only in gp4 or higher profiles. - (float4)(sampler2DARRAY, float3/float4 s, {float2 dx, dy},[int texeloffset])",
tex2DARRAYbias = fn "performs a texture lookup with bias in a given sampler (as .w). - (float4)(sampler2DARRAY, float4 s, [int texeloffset])",
tex2DARRAYfetch = fn "performs an unfiltered texture lookup in a given sampler (lod as .w). - (float4)(sampler2DARRAY, int4 s, [int texeloffset])",
tex2DARRAYlod = fn "performs a texture lookup with a specified level of detail in a given sampler (lod as .w) - (float4)(sampler2DARRAY, float4 s, [int texeloffset])",
tex2DARRAYproj = fn "performs a texture lookup with projection in a given sampler. May perform a shadow comparison if argument for shadow comparison is provided. (proj in .w) - (float4)(sampler2DARRAY, float4 s, [int texeloff])",
tex2DARRAYsize = fn "returns the size of a given texture image for a given level of detail. (only gp4 profiles) - (int3)(sampler2DARRAY, int lod)",
texCUBEARRAY = fn "performs a texture lookup in a given CUBE sampler array. May also use pre computed derivatives if those are provided. Texeloffset only in gp4 or higher profiles. - (float4)(samplerCUBEARRAY, float4 s, {float3 dx, dy},[int texeloffset])",
texCUBEARRAYsize = fn "returns the size of a given texture image for a given level of detail. (only gp4 profiles) - (int3)(samplerCUBEARRAY, int lod)",
unpack_4ubyte = fn "interprets the single float as 4 normalized unsigned bytes and returns the vector. (only nv/gp4 profiles) - (float4)(float)",
pack_4ubyte = fn "packs the floats into a single storing as normalized unsigned bytes.(only nv/gp4 profiles) - (float)(float4)",
unpack_4byte = fn "interprets the single float as 4 normalized signed bytes and returns the vector. (only nv/gp4 profiles) - (float4)(float)",
pack_4ubyte = fn "packs the floats into a single storing as normalized signed bytes.(only nv/gp4 profiles) - (float)(float4)",
unpack_4ushort = fn "interprets the single float as 2 normalized unsigned shorts and returns the vector. (only nv/gp4 profiles) - (float2)(float)",
pack_4ushort = fn "packs the floats into a single storing as normalized unsigned shorts.(only nv/gp4 profiles) - (float)(float2)",
unpack_2half = fn "interprets the single float as 2 16-bit floats and returns the vector. (only nv/gp4 profiles) - (float2)(float)",
pack_2half = fn "packs the floats into a single storing as 16-bit floats.(only nv/gp4 profiles) - (float)(float2)",
}
local keyw =
[[int half float float3 float4 float2 float3x3 float3x4 float4x3 float4x4
float1x2 float2x1 float2x2 float2x3 float3x2 float1x3 float3x1 float4x1 float1x4
float2x4 float4x2 double1x4 double4x4 double4x2 double4x3 double3x4 double2x4 double1x4
double half half2 half3 half4 int2 int3 uint uint2 uint3 uint4
int4 bool bool2 bool3 bool4 string struct typedef
usampler usampler1D usampler2D usampler3D usamplerRECT usamplerCUBE isampler1DARRAY usampler2DARRAY usamplerCUBEARRAY
isampler isampler1D isampler2D isampler3D isamplerRECT isamplerCUBE isampler1DARRAY isampler2DARRAY isamplerCUBEARRAY
usamplerBUF isamplerBUF samplerBUF
sampler sampler1D sampler2D sampler3D samplerRECT samplerCUBE sampler1DARRAY sampler2DARRAY samplerCUBEARRAY
texture texture1D texture2D texture3D textureRECT textureCUBE texture1DARRAY texture2DARRAY textureCUBEARRAY
decl do else extern false for if in inline inout out pass
pixelshader return shared static string technique true
uniform vector vertexshader void volatile while
asm compile const auto break case catch char class const_cast continue default delete
dynamic_cast enum explicit friend goto long mutable namespace new operator private protected
public register reinterpret_case short signed sizeof static_cast switch template this throw
try typename union unsigned using virtual
POSITION PSIZE DIFFUSE SPECULAR TEXCOORD FOG COLOR COLOR0 COLOR1 COLOR2 COLOR3 TEXCOORD0 TEXCOORD1 TEXCOORD2 TEXCOORD3
TEXCOORD4 TEXCOORD5 TEXCOORD6 TEXCOORD7 TEXCOORD8 TEXCOORD9 TEXCOORD10 TEXCOORD11 TEXCOORD12 TEXCOORD13 TEXCOORD14
TEXCOORD15
NORMAL WPOS
ATTR0 ATTR1 ATTR2 ATTR3 ATTR4 ATTR5 ATTR6 ATTR7 ATTR8 ATTR9 ATTR10 ATTR11 ATTR12 ATTR13 ATTR14 ATTR15
TEXUNIT0 TEXUNIT1 TEXUNIT2 TEXUNIT3 TEXUNIT4 TEXUNIT5 TEXUNIT6 TEXUNIT7 TEXUNIT8 TEXUNIT9 TEXUNIT10 TEXUNIT11 TEXUNIT12
TEXUNIT13 TEXUNIT14 TEXUNIT15
PROJ PROJECTION PROJECTIONMATRIX PROJMATRIX
PROJMATRIXINV PROJINV PROJECTIONINV PROJINVERSE PROJECTIONINVERSE PROJINVMATRIX PROJECTIONINVMATRIX PROJINVERSEMATRIX PROJECTIONINVERSEMATRIX
VIEW VIEWMATRIX VIEWMATRIXINV VIEWINV VIEWINVERSE VIEWINVERSEMATRIX VIEWINVMATRIX
VIEWPROJECTION VIEWPROJ VIEWPROJMATRIX VIEWPROJECTIONMATRIX
WORLD WORLDMATRIX WORLDVIEW WORLDVIEWMATRIX
WORLDVIEWPROJ WORLDVIEWPROJECTION WORLDVIEWPROJMATRIX WORLDVIEWPROJECTIONMATRIX
VIEWPORTSIZE VIEWPORTDIMENSION
VIEWPORTSIZEINV VIEWPORTSIZEINVERSE VIEWPORTDIMENSIONINV VIEWPORTDIMENSIONINVERSE INVERSEVIEWPORTDIMENSIONS
FOGCOLOR FOGDISTANCE CAMERAWORLDPOS CAMERAWORLDDIR
CENTROID FLAT NOPERSPECTIVE FACE PRIMITIVEID VERTEXID
]]
-- keywords - shouldn't be left out
for w in keyw:gmatch("([_%w]+)") do
api[w] = {type="keyword"}
end
return api
-- authors: Luxinia Dev (Eike Decker & Christoph Kubisch)
---------------------------------------------------------
local function fn (description)
local description2,returns,args = description:match("(.+)%-%s*(%b())%s*(%b())")
if not description2 then
return {type="function",description=description,
returns="(?)"}
end
return {type="function",description=description2,
returns=returns:gsub("^%s+",""):gsub("%s+$",""), args = args}
end
local function val (description)
return {type="value",description = description}
end
-- docs
local api = {
abs = fn "returns absolute value of scalars and vectors. - (typeN)(typeN)",
acos = fn "returns arccosine of scalars and vectors. - (typeN)(typeN)",
all = fn "returns true if a boolean scalar or all components of a boolean vector are true. - (bool)(boolN)",
any = fn "returns true if a boolean scalar or any component of a boolean vector is true. - (bool)(boolN)",
asin = fn "returns arcsine of scalars and vectors. - (typeN)(typeN)",
atan = fn "returns arctangent of scalars and vectors. - (typeN)(typeN)",
atan2 = fn "returns the arctangent of y/x. atan2 is well defined for every point other than the origin, even if x equals 0 and y does not equal 0. - (typeN)(typeN y, typeN x)",
ceil = fn "returns smallest integer not less than a scalar or each vector component. - (typeN)(typeN)",
clamp = fn "returns x clamped to the range [a,b]. - (typeN)(typeN x, a, b)",
clip = fn "conditionally (<0) kill a pixel before output. - ()(typeN)",
cos = fn "returns cosine of scalars and vectors. - (typeN)(typeN)",
cosh = fn "returns hyperbolic cosine of scalars and vectors. - (typeN)(typeN)",
cross = fn "returns the cross product of two three-component vectors. - (type3)(type3 a, b)",
ddx = fn "returns approximate partial derivative with respect to window-space X. - (typeN)(typeN)",
ddy = fn "returns approximate partial derivative with respect to window-space Y. - (typeN)(typeN)",
degrees = fn "converts values of scalars and vectors from radians to degrees. - (typeN)(typeN)",
determinant = fn "returns the scalar determinant of a square matrix. - (float)(floatNxN)",
distance = fn "return the Euclidean distance between two points. - (typeN)(typeN a, b)",
dot = fn "returns the scalar dot product of two vectors. - (type)(typeN a, b)",
exp = fn "returns the base-e exponential of scalars and vectors. - (typeN)(typeN)",
exp2 = fn "returns the base-2 exponential of scalars and vectors. - (typeN)(typeN)",
faceforward = fn "returns a normal as-is if a vertex's eye-space position vector points in the opposite direction of a geometric normal, otherwise return the negated version of the normal. - (typeN)(typeN Nperturbated, Incident, Ngeometric)",
floatToIntBits = fn "returns the 32-bit integer representation of an IEEE 754 floating-point scalar or vector - (intN)(floatN)",
floatToRawIntBits = fn "returns the raw 32-bit integer representation of an IEEE 754 floating-point scalar or vector. - (intN)(floatN)",
floor = fn "returns largest integer not greater than a scalar or each vector component. - (typeN)(typeN)",
fmod = fn "returns the remainder of x/y with the same sign as x. - (typeN)(typeN x, y)",
frac = fn "returns the fractional portion of a scalar or each vector component. - (typeN)(typeN)",
frexp = fn "splits scalars and vectors into normalized fraction and a power of 2. - (typeN)(typeN x, out typeN e)",
fwidth = fn "returns sum of approximate window-space partial derivatives magnitudes. - (typeN)(typeN)",
intBitsToFloat = fn "returns the float value corresponding to a given bit represention.of a scalar int value or vector of int values. - (floatN)(intN)",
isfinite = fn "test whether or not a scalar or each vector component is a finite value. - (boolN)(typeN)",
isinf = fn "test whether or not a scalar or each vector component is infinite. - (boolN)(typeN)",
isnan = fn "test whether or not a scalar or each vector component is not-a-number. - (boolN)(typeN)",
ldexp = fn "returns x times 2 rained to n. - (typeN)(typeN a, n)",
length = fn "return scalar Euclidean length of a vector. - (type)(typeN)",
lerp = fn "lerp - returns linear interpolation of two scalars or vectors based on a weight. - (typeN)(typeN a, b, weight)",
lit = fn "computes lighting coefficients for ambient(x), diffuse(y), and specular(z) lighting contributions (w=1). - (type4)(type NdotL, NdotH, specshiny)",
log = fn "returns the natural logarithm of scalars and vectors. - (typeN)(typeN)",
log10 = fn "returns the base-10 logarithm of scalars and vectors. - (typeN)(typeN)",
log2 = fn "returns the base-2 logarithm of scalars and vectors. - (typeN)(typeN)",
max = fn "returns the maximum of two scalars or each respective component of two vectors. - (typeN)(typeN a, b)",
min = fn "returns the minimum of two scalars or each respective component of two vectors. - (typeN)(typeN a, b)",
mul = fn "Returns the vector result of multiplying a matrix M by a column vector v; a row vector v by a matrix M; or a matrix A by a second matrix B. - (typeN)(typeNxN/typeN a, typeN/typeNxN b)",
normalize = fn "Returns the normalized version of a vector, meaning a vector in the same direction as the original vector but with a Euclidean length of one. - (typeN)(typeN)",
pow = fn "returns x to the y-th power of scalars and vectors. - (typeN)(typeN x, y)",
radians = fn "converts values of scalars and vectors from degrees to radians. - (typeN)(typeN)",
reflect = fn "returns the reflectiton vector given an incidence vector and a normal vector. - (typeN)(typeN incidence, normal)",
refract = fn "computes a refraction vector. - (typeN)(typeN incidence, normal, type eta)",
round = fn "returns the rounded value of scalars or vectors. - (typeN)(typeN a)",
rsqrt = fn "returns reciprocal square root of scalars and vectors. 1/sqrt. - (typeN)(typeN)",
saturate = fn "returns x saturated to the range [0,1]. - (typeN)(typeN)",
sign = fn "returns sign (1 or -1) of scalar or each vector component. - (typeN)(typeN)",
sin = fn "returns sine of scalars and vectors. - (typeN)(typeN)",
sincos = fn "returns sine of scalars and vectors. - ()(typeN x, out typeN sin, out typeN cos)",
sinh = fn "returns hyperbolic sine of scalars and vectors. - (typeN)(typeN)",
sqrt = fn "returns square root of scalars and vectors. - (typeN)(typeN)",
step = fn "implement a step function returning either zero or one (a <= b). - (typeN)(typeN a, b)",
tan = fn "returns tangent of scalars and vectors. - (typeN)(typeN)",
tanh = fn "returns hyperbolic tangent of scalars and vectors. - (typeN)(typeN)",
transpose = fn "returns transpose matrix of a matrix. - (typeRxC)(typeCxR)",
trunc = fn "returns largest integer not greater than a scalar or each vector component. - (typeN)(typeN)",
tex1D = fn "performs a texture lookup in a given 1D sampler and, in some cases, a shadow comparison (as .y coord). May also use pre computed derivatives if those are provided. Texeloffset only in gp4 or higher profiles. - (float4)(sampler1D, float/float2 s, |float dx, dy|,[int texeloffset])",
tex1Dbias = fn "performs a texture lookup with bias in a given sampler (as .w). - (float4)(sampler1D, float4 s, [int texeloffset])",
tex1Dcmpbias = fn "performs a texture lookup with bias and shadow compare in a given sampler (compare as .y, bias as .w). - (float4)(sampler1D, float4 s, [int texeloffset])",
tex1Dcmplod = fn "performs a texture lookup with a specified level of detail and a shadow compare in a given sampler (compare as .y, lod as .w). - (float4)(sampler1D, float4 s, [int texeloffset])",
tex1Dfetch = fn "performs an unfiltered texture lookup in a given sampler (lod as .w). - (float4)(sampler1D, int4 s, [int texeloffset])",
tex1Dlod = fn "performs a texture lookup with a specified level of detail in a given sampler (lod as .w) - (float4)(sampler1D, float4 s, [int texeloffset])",
tex1Dproj = fn "performs a texture lookup with projection in a given sampler. May perform a shadow comparison if argument for shadow comparison is provided. (shadow in .y for float3 coord, proj in .y or .z) - (float4)(sampler1D, float2/float3 s, [int texeloff])",
tex1Dsize = fn "returns the size of a given texture image for a given level of detail. (only gp4 profiles) - (int3)(sampler1D, int lod)",
tex2D = fn "performs a texture lookup in a given 2D sampler and, in some cases, a shadow comparison (as .z coord). May also use pre computed derivatives if those are provided. Texeloffset only in gp4 or higher profiles. - (float4)(sampler2D, float2/float3 s, |float2 dx, dy|,[int texeloffset])",
tex2Dbias = fn "performs a texture lookup with bias in a given sampler (as .w). - (float4)(sampler2D, float4 s, [int texeloffset])",
tex2Dcmpbias = fn "performs a texture lookup with bias and shadow compare in a given sampler (compare as .z, bias as .w). - (float4)(sampler2D, float4 s, [int texeloffset])",
tex2Dcmplod = fn "performs a texture lookup with a specified level of detail and a shadow compare in a given sampler (compare as .y, lod as .w). - (float4)(sampler2D, float4 s, [int texeloffset])",
tex2Dfetch = fn "performs an unfiltered texture lookup in a given sampler (lod as .w). - (float4)(sampler2D, int4 s, [int texeloffset])",
tex2Dlod = fn "performs a texture lookup with a specified level of detail in a given sampler (lod as .w) - (float4)(sampler2D, float4 s, [int texeloffset])",
tex2Dproj = fn "performs a texture lookup with projection in a given sampler. May perform a shadow comparison if argument for shadow comparison is provided. (shadow in .z for float3 coord, proj in .z or .w) - (float4)(sampler2D, float3/float4 s, [int texeloff])",
tex2Dsize = fn "returns the size of a given texture image for a given level of detail. (only gp4 profiles) - (int3)(sampler2D, int lod)",
tex2Dgather = fn "returns 4 texels of a given single channel texture image for a given level of detail. (only gp4 profiles) - (int3)(sampler2D, int lod)",
tex3D = fn "performs a texture lookup in a given 3D sampler. May also use pre computed derivatives if those are provided. Texeloffset only in gp4 or higher profiles. - (float4)(sampler3D, float3 s, {float3 dx, dy},[int texeloffset])",
tex3Dbias = fn "performs a texture lookup with bias in a given sampler (as .w). - (float4)(sampler3D, float4 s, [int texeloffset])",
tex3Dfetch = fn "performs an unfiltered texture lookup in a given sampler (lod as .w). - (float4)(sampler3D, int4 s, [int texeloffset])",
tex3Dlod = fn "performs a texture lookup with a specified level of detail in a given sampler (lod as .w) - (float4)(sampler3D, float4 s, [int texeloffset])",
tex3Dproj = fn "performs a texture lookup with projection in a given sampler. (proj in .w) - (float4)(sampler3D, float4 s, [int texeloff])",
tex3Dsize = fn "returns the size of a given texture image for a given level of detail. (only gp4 profiles) - (int3)(sampler3D, int lod)",
texBUF = fn "performs an unfiltered texture lookup in a given texture buffer sampler. (only gp4 profiles) - (float4)(samplerBUF, int s)",
texBUFsize = fn "returns the size of a given texture image for a given level of detail. (only gp4 profiles) - (int3)(samplerBUF, int lod)",
texRBUF = fn "performs a multi-sampled texture lookup in a renderbuffer. (only gp4 profiles) - (float4)(samplerRBUF, int2 s, int sample)",
texRBUFsize = fn "returns the size of a given renderbuffer. (only gp4 profiles) - (int2)(samplerBUF)",
texCUBE = fn "performs a texture lookup in a given CUBE sampler and, in some cases, a shadow comparison (float4 coord). May also use pre computed derivatives if those are provided. Texeloffset only in gp4 or higher profiles. - (float4)(samplerCUBE, float3/float4 s, |float3 dx, dy|)",
texCUBEbias = fn "performs a texture lookup with bias in a given sampler (as .w). - (float4)(sampler1D, float4 s, [int texeloffset])",
texCUBElod = fn "performs a texture lookup with a specified level of detail in a given sampler (lod as .w) - (float4)(sampler1D, float4 s, [int texeloffset])",
texCUBEproj = fn "performs a texture lookup with projection in a given sampler. (proj in .w) - (float4)(samplerCUBE, float4 s)",
texCUBEsize = fn "returns the size of a given texture image for a given level of detail. (only gp4 profiles) - (int3)(sampler1D, int lod)",
texRECT = fn "performs a texture lookup in a given RECT sampler and, in some cases, a shadow comparison (as .z). May also use pre computed derivatives if those are provided. Texeloffset only in gp4 or higher profiles. - (float4)(samplerRECT, float2/float3 s, |float2 dx, dy|, [int texeloff])",
texRECTbias = fn "performs a texture lookup with bias in a given sampler (as .w). - (float4)(samplerRECT, float4 s, [int texeloffset])",
texRECTfetch = fn "performs an unfiltered texture lookup in a given sampler (lod as .w). - (float4)(samplerRECT, int4 s, [int texeloffset])",
texRECTlod = fn "performs a texture lookup with a specified level of detail in a given sampler (lod as .w) - (float4)(samplerRECT, float4 s, [int texeloffset])",
texRECTproj = fn "performs a texture lookup with projection in a given sampler. May perform a shadow comparison if argument for shadow comparison is provided. (shadow in .z for float3 coord, proj in .z or .w) - (float4)(samplerRECT, float3/float4 s, [int texeloff])",
texRECTsize = fn "returns the size of a given texture image for a given level of detail. (only gp4 profiles) - (int3)(samplerRECT, int lod)",
tex1DARRAY = fn "performs a texture lookup in a given 1D sampler array and, in some cases, a shadow comparison (as .z). May also use pre computed derivatives if those are provided. Texeloffset only in gp4 or higher profiles. - (float4)(sampler1DARRAY, float2/float3 s, {float dx, dy},[int texeloffset])",
tex1DARRAYbias = fn "performs a texture lookup with bias in a given sampler (as .w). - (float4)(sampler1DARRAY, float4 s, [int texeloffset])",
tex1DARRAYcmpbias = fn "performs a texture lookup with bias and shadow compare in a given sampler (layer as .y, compare as .z, bias as .w). - (float4)(sampler1DARRAY, float4 s, [int texeloffset])",
tex1DARRAYcmplod = fn "performs a texture lookup with a specified level of detail and a shadow compare in a given sampler (compare as .z, lod as .w). - (float4)(sampler1DARRAY, float4 s, [int texeloffset])",
tex1DARRAYfetch = fn "performs an unfiltered texture lookup in a given sampler (lod as .z). - (float4)(sampler1DARRAY, int3 s, [int texeloffset])",
tex1DARRAYlod = fn "performs a texture lookup with a specified level of detail in a given sampler (lod as .z) - (float4)(sampler1DARRAY, float3 s, [int texeloffset])",
tex1DARRAYproj = fn "performs a texture lookup with projection in a given sampler. May perform a shadow comparison if argument for shadow comparison is provided. (shadow in .z for float3 coord, proj in .z or .w) - (float4)(sampler1DARRAY, float3/float4 s, [int texeloff])",
tex1DARRAYsize = fn "returns the size of a given texture image for a given level of detail. (only gp4 profiles) - (int3)(sampler1DARRAY, int lod)",
tex2DARRAY = fn "performs a texture lookup in a given 2D sampler array and, in some cases, a shadow comparison (as .w coord). May also use pre computed derivatives if those are provided. Texeloffset only in gp4 or higher profiles. - (float4)(sampler2DARRAY, float3/float4 s, {float2 dx, dy},[int texeloffset])",
tex2DARRAYbias = fn "performs a texture lookup with bias in a given sampler (as .w). - (float4)(sampler2DARRAY, float4 s, [int texeloffset])",
tex2DARRAYfetch = fn "performs an unfiltered texture lookup in a given sampler (lod as .w). - (float4)(sampler2DARRAY, int4 s, [int texeloffset])",
tex2DARRAYlod = fn "performs a texture lookup with a specified level of detail in a given sampler (lod as .w) - (float4)(sampler2DARRAY, float4 s, [int texeloffset])",
tex2DARRAYproj = fn "performs a texture lookup with projection in a given sampler. May perform a shadow comparison if argument for shadow comparison is provided. (proj in .w) - (float4)(sampler2DARRAY, float4 s, [int texeloff])",
tex2DARRAYsize = fn "returns the size of a given texture image for a given level of detail. (only gp4 profiles) - (int3)(sampler2DARRAY, int lod)",
texCUBEARRAY = fn "performs a texture lookup in a given CUBE sampler array. May also use pre computed derivatives if those are provided. Texeloffset only in gp4 or higher profiles. - (float4)(samplerCUBEARRAY, float4 s, {float3 dx, dy},[int texeloffset])",
texCUBEARRAYsize = fn "returns the size of a given texture image for a given level of detail. (only gp4 profiles) - (int3)(samplerCUBEARRAY, int lod)",
unpack_4ubyte = fn "interprets the single float as 4 normalized unsigned bytes and returns the vector. (only nv/gp4 profiles) - (float4)(float)",
pack_4ubyte = fn "packs the floats into a single storing as normalized unsigned bytes.(only nv/gp4 profiles) - (float)(float4)",
unpack_4byte = fn "interprets the single float as 4 normalized signed bytes and returns the vector. (only nv/gp4 profiles) - (float4)(float)",
pack_4ubyte = fn "packs the floats into a single storing as normalized signed bytes.(only nv/gp4 profiles) - (float)(float4)",
unpack_4ushort = fn "interprets the single float as 2 normalized unsigned shorts and returns the vector. (only nv/gp4 profiles) - (float2)(float)",
pack_4ushort = fn "packs the floats into a single storing as normalized unsigned shorts.(only nv/gp4 profiles) - (float)(float2)",
unpack_2half = fn "interprets the single float as 2 16-bit floats and returns the vector. (only nv/gp4 profiles) - (float2)(float)",
pack_2half = fn "packs the floats into a single storing as 16-bit floats.(only nv/gp4 profiles) - (float)(float2)",
}
local keyw =
[[int half float float3 float4 float2 float3x3 float3x4 float4x3 float4x4
float1x2 float2x1 float2x2 float2x3 float3x2 float1x3 float3x1 float4x1 float1x4
float2x4 float4x2 double1x4 double4x4 double4x2 double4x3 double3x4 double2x4 double1x4
double half half2 half3 half4 int2 int3 uint uint2 uint3 uint4
int4 bool bool2 bool3 bool4 string struct typedef
usampler usampler1D usampler2D usampler3D usamplerRECT usamplerCUBE isampler1DARRAY usampler2DARRAY usamplerCUBEARRAY
isampler isampler1D isampler2D isampler3D isamplerRECT isamplerCUBE isampler1DARRAY isampler2DARRAY isamplerCUBEARRAY
usamplerBUF isamplerBUF samplerBUF
sampler sampler1D sampler2D sampler3D samplerRECT samplerCUBE sampler1DARRAY sampler2DARRAY samplerCUBEARRAY
texture texture1D texture2D texture3D textureRECT textureCUBE texture1DARRAY texture2DARRAY textureCUBEARRAY
decl do else extern false for if in inline inout out pass
pixelshader return shared static string technique true
uniform vector vertexshader void volatile while
asm compile const auto break case catch char class const_cast continue default delete
dynamic_cast enum explicit friend goto long mutable namespace new operator private protected
public register reinterpret_case short signed sizeof static_cast switch template this throw
try typename union unsigned using virtual
POSITION PSIZE DIFFUSE SPECULAR TEXCOORD FOG COLOR COLOR0 COLOR1 COLOR2 COLOR3 TEXCOORD0 TEXCOORD1 TEXCOORD2 TEXCOORD3
TEXCOORD4 TEXCOORD5 TEXCOORD6 TEXCOORD7 TEXCOORD8 TEXCOORD9 TEXCOORD10 TEXCOORD11 TEXCOORD12 TEXCOORD13 TEXCOORD14
TEXCOORD15
NORMAL WPOS
ATTR0 ATTR1 ATTR2 ATTR3 ATTR4 ATTR5 ATTR6 ATTR7 ATTR8 ATTR9 ATTR10 ATTR11 ATTR12 ATTR13 ATTR14 ATTR15
TEXUNIT0 TEXUNIT1 TEXUNIT2 TEXUNIT3 TEXUNIT4 TEXUNIT5 TEXUNIT6 TEXUNIT7 TEXUNIT8 TEXUNIT9 TEXUNIT10 TEXUNIT11 TEXUNIT12
TEXUNIT13 TEXUNIT14 TEXUNIT15
PROJ PROJECTION PROJECTIONMATRIX PROJMATRIX
PROJMATRIXINV PROJINV PROJECTIONINV PROJINVERSE PROJECTIONINVERSE PROJINVMATRIX PROJECTIONINVMATRIX PROJINVERSEMATRIX PROJECTIONINVERSEMATRIX
VIEW VIEWMATRIX VIEWMATRIXINV VIEWINV VIEWINVERSE VIEWINVERSEMATRIX VIEWINVMATRIX
VIEWPROJECTION VIEWPROJ VIEWPROJMATRIX VIEWPROJECTIONMATRIX
WORLD WORLDMATRIX WORLDVIEW WORLDVIEWMATRIX
WORLDVIEWPROJ WORLDVIEWPROJECTION WORLDVIEWPROJMATRIX WORLDVIEWPROJECTIONMATRIX
VIEWPORTSIZE VIEWPORTDIMENSION
VIEWPORTSIZEINV VIEWPORTSIZEINVERSE VIEWPORTDIMENSIONINV VIEWPORTDIMENSIONINVERSE INVERSEVIEWPORTDIMENSIONS
FOGCOLOR FOGDISTANCE CAMERAWORLDPOS CAMERAWORLDDIR
CENTROID FLAT NOPERSPECTIVE FACE PRIMITIVEID VERTEXID
]]
-- keywords - shouldn't be left out
for w in keyw:gmatch("([_%w]+)") do
api[w] = {type="keyword"}
end
return api

View File

@@ -1,200 +1,200 @@
-- authors: Luxinia Dev (Eike Decker & Christoph Kubisch)
---------------------------------------------------------
-- function helpers
local function fn (description)
local description2,returns,args = description:match("(.+)%-%s*(%b())%s*(%b())")
if not description2 then
return {type="function",description=description,
returns="(?)"}
end
returns = returns:gsub("^%s+",""):gsub("%s+$","")
local ret = returns:sub(2,-2)
local vt = ret:match("^%[?string") and "string"
vt = vt or ret:match("^%[?table") and "table"
vt = vt or ret:match("^%[?file") and "io"
return {type="function",description=description2,
returns=returns, args = args, valuetype = vt}
end
local function val (description)
return {type="value",description = description}
end
-- docs
local api = {
table = {
description = "Table functions",
type = "lib",
childs = {
concat = fn "concatenates an array of elements - (string)(table,[sep])",
insert = fn "inserts an element into an array - ()(table,idx,element)",
remove = fn "removes an element from an array - (element)(table,idx)",
maxn = fn "Returns the largest positive numerical index of the given table, or zero if the table has no positive numerical indices. - (number)(table)",
sort = fn "Sorts table elements in a given order, in-place, from table[1] to table[n], where n is the length of the table. - ()(table,[comp])"
}
},
math = {
type = "lib",
description = "Math functions",
childs = {
abs = fn "Returns the absolute value of x. - (number)(number)",
acos = fn "Returns the arc cosine of x (in radians). - (number)(number)",
asin = fn "Returns the arc sine of x (in radians). - (number)(number)",
atan = fn "Returns the arc tangent of x (in radians). - (number)(number)",
atan2 = fn "Returns the arc tangent of x/y (in radians), but uses the signs of both parameters to find the quadrant of the result. (It also handles correctly the case of y being zero.) - (number)(number,number)",
ceil = fn "Returns the smallest integer larger than or equal to x. - (number)(number)",
cos = fn "Returns the cosine of x (assumed to be in radians).",
cosh = fn "Returns the hyperbolic cosine of x.",
deg = fn "Returns the angle x (given in radians) in degrees.",
exp = fn "Returns the the value ex.",
floor = fn "Returns the largest integer smaller than or equal to x.",
fmod = fn "Returns the remainder of the division of x by y.",
frexp = fn "Returns m and e such that x = m2e, e is an integer and the absolute value of m is in the range [0.5, 1) (or zero when x is zero).",
huge = val "The value HUGE_VAL, a value larger than or equal to any other numerical value.",
ldexp = fn "Returns m2e (e should be an integer).",
log = fn "Returns the natural logarithm of x.",
log10 = fn "Returns the base-10 logarithm of x.",
max = fn "Returns the maximum value among its arguments.",
min = fn "Returns the minimum value among its arguments.",
modf = fn "Returns two numbers, the integral part of x and the fractional part of x.",
pi = val "The value PI.",
pow = fn "Returns xy. (You can also use the expression x^y to compute this value.)",
rad = fn "Returns the angle x (given in degrees) in radians.",
random = fn "This function is an interface to the simple pseudo-random generator function rand provided by ANSI C. (No guarantees can be given for its statistical properties.) When called without arguments, returns a pseudo-random real number in the range [0,1). When called with a number m, math.random returns a pseudo-random integer in the range [1, m]. When called with two numbers m and n, math.random returns a pseudo-random integer in the range [m, n].",
randomseed = fn "Sets x as the \"seed\" for the pseudo-random generator: equal seeds produce equal sequences of numbers.",
sin = fn"Returns the sine of x (assumed to be in radians).",
sinh = fn"Returns the hyperbolic sine of x.",
sqrt = fn "Returns the square root of x. (You can also use the expression x^0.5 to compute this value.)",
tan = fn "Returns the tangent of x (assumed to be in radians).",
tanh = fn "Returns the hyperbolic tangent of x. "
}
},
pairs = fn "returns an iterator function for the given table - (function)(table)",
ipairs = fn "returns an iterator function for the given table - (function)(table)",
xpcall = fn "calls a function in protected mode - (boolean success, [error string / result])(called,errorfunc)",
pcall = fn "calls a function in protected mode - (boolean success, [error string / result])(called, args ...)",
print = fn "prints out the arguments - ()(...)",
assert = fn "error checking, if first arg is false, error message is thrown - (result)(compute,errormsg)",
collectgarbage = fn "garbage collector manipulation - (...)(...)",
dofile = fn "compile and execute a file - (...)(...)",
error = fn "raise an error - (...)(...)",
getfenv = fn "get the function environment for a function - (...)(...)",
getmetatable = fn "not yet - (...)(...)",
load = fn "not yet - (...)(...)",
loadfile = fn "not yet - (...)(...)",
loadstring = fn "not yet - (...)(...)",
next = fn "not yet - (...)(...)",
rawequal = fn "not yet - (...)(...)",
rawget = fn "not yet - (...)(...)",
rawset = fn "not yet - (...)(...)",
select = fn "not yet - (...)(...)",
setfenv = fn "not yet - (...)(...)",
setmetatable = fn "not yet - (...)(...)",
tonumber = fn "not yet - (number)(...)",
tostring = fn "not yet - (string)(...)",
type = fn "not yet - (string)(...)",
unpack = fn "not yet - (...)(...)",
module = fn "Creates a module. - (?)(name,...)",
require = fn "Loads the given module. - (?)(name)",
package = {
type = "table",
description = "package info",
childs = {
cpath = val "The path used by require to search for a C loader. ",
loaded = val "A table used by require to control which modules are already loaded.",
loadlib = fn "Dynamically links the host program with the C library libname. - (?)(libname, funcname)",
path = val "The path used by require to search for a Lua loader. ",
preload = val "A table to store loaders for specific modules (see require). ",
seeall = fn "Sets a metatable for module with its __index field referring to the global environment, so that this module inherits values from the global environment. To be used as an option to function module. - (?)(module)"
}
},
string = {
type = "lib",
description = "string lib",
childs = {
byte = fn "Returns the internal numerical codes of the characters s[i], s[i+1], ···, s[j]. The default value for i is 1; the default value for j is i. - (number)(string [, i [, j]])",
char = fn "Receives zero or more integers. Returns a string with length equal to the number of arguments, in which each character has the internal numerical code equal to its corresponding argument. - (string)(...)",
dump = fn "Returns a string containing a binary representation of the given function, so that a later loadstring on this string returns a copy of the function. function must be a Lua function without upvalues. - (string)(func)",
find = fn "Looks for the first match of pattern in the string s. If it finds a match, then find returns the indices of s where this occurrence starts and ends; otherwise, it returns nil. A third, optional numerical argument init specifies where to start the search; its default value is 1 and may be negative. A value of true as a fourth, optional argument plain turns off the pattern matching facilities, so the function does a plain \"find substring\" operation, with no characters in pattern being considered \"magic\". Note that if plain is given, then init must be given as well. - (number,number)(string, pattern [, init [, plain]])",
format = fn "Returns a formatted version of its variable number of arguments following the description given in its first argument (which must be a string). The format string follows the same rules as the printf family of standard C functions. The only differences are that the options/modifiers *, l, L, n, p, and h are not supported and that there is an extra option, q. The q option formats a string in a form suitable to be safely read back by the Lua interpreter: the string is written between double quotes, and all double quotes, newlines, embedded zeros, and backslashes in the string are correctly escaped when written. - (string)(formatstring, ···)",
gmatch = fn "Returns an iterator function that, each time it is called, returns the next captures from pattern over string s. - (func)(string, pattern)",
gsub = fn "Returns a copy of s in which all occurrences of the pattern have been replaced by a replacement string specified by repl, which may be a string, a table, or a function. gsub also returns, as its second value, the total number of substitutions made. - (string,number)(string, pattern, repl [, n])",
len = fn "Receives a string and returns its length. The empty string '' has length 0. Embedded zeros are counted, so 'a\\000bc\\000' has length 5. - (number)(string)",
lower = fn "Receives a string and returns a copy of this string with all uppercase letters changed to lowercase. All other characters are left unchanged. The definition of what an uppercase letter is depends on the current locale. - (string)(string)",
match = fn "Looks for the first match of pattern in the string s. If it finds one, then match returns the captures from the pattern; otherwise it returns nil. If pattern specifies no captures, then the whole match is returned. A third, optional numerical argument init specifies where to start the search; its default value is 1 and may be negative. - (string,...)(string, pattern [, init])",
rep = fn "Returns a string that is the concatenation of n copies of the string s. - (string)(string s, n)",
reverse = fn "Returns a string that is the string s reversed. - (string)(string)",
sub = fn "Returns the substring of s that starts at i and continues until j; i and j may be negative. If j is absent, then it is assumed to be equal to -1 (which is the same as the string length). In particular, the call string.sub(s,1,j) returns a prefix of s with length j, and string.sub(s, -i) returns a suffix of s with length i. - (string)(string, i [, j])",
upper = fn "Receives a string and returns a copy of this string with all lowercase letters changed to uppercase. All other characters are left unchanged. The definition of what a lowercase letter is depends on the current locale. - (string)(string)",
}
},
coroutine = {
type = "lib",
description = "Lua supports coroutines, also called collaborative multithreading. A coroutine in Lua represents an independent thread of execution. Unlike threads in multithread systems, however, a coroutine only suspends its execution by explicitly calling a yield function.",
childs = {
create = fn 'Creates a new coroutine, with body f. f must be a Lua function. Returns this new coroutine, an object with type "thread". - (thread)(function)',
resume = fn 'Starts or continues the execution of coroutine co. The first time you resume a coroutine, it starts running its body. The values val1, ··· are passed as the arguments to the body function. If the coroutine has yielded, resume restarts it; the values val1, ··· are passed as the results from the yield. - (boolean success, ...)(coroutine,...)',
running = fn 'Returns the running coroutine, or nil when called by the main thread. - ([thread])()',
status = fn 'Returns the status of coroutine co, as a string: "running", if the coroutine is running (that is, it called status); "suspended", if the coroutine is suspended in a call to yield, or if it has not started running yet; "normal" if the coroutine is active but not running (that is, it has resumed another coroutine); and "dead" if the coroutine has finished its body function, or if it has stopped with an error. - (status)(coroutine)',
wrap = fn 'Creates a new coroutine, with body f. f must be a Lua function. Returns a function that resumes the coroutine each time it is called. Any arguments passed to the function behave as the extra arguments to resume. Returns the same values returned by resume, except the first boolean. In case of error, propagates the error. - (function)(function)',
yield = fn 'Suspends the execution of the calling coroutine. The coroutine cannot be running a C function, a metamethod, or an iterator. Any arguments to yield are passed as extra results to resume. - (...)(...)'
}
},
io = {
type = "lib",
description = "The I/O library provides two different styles for file manipulation. The first one uses implicit file descriptors; that is, there are operations to set a default input file and a default output file, and all input/output operations are over these default files. The second style uses explicit file descriptors. ",
childs = {
close = fn'Equivalent to file:close(). Without a file, closes the default output file. - ()([file])',
flush = fn'Equivalent to file:flush over the default output file. - ()([file])',
input = fn'When called with a file name, it opens the named file (in text mode), and sets its handle as the default input file. When called with a file handle, it simply sets this file handle as the default input file. When called without parameters, it returns the current default input file. - ([in])([file])',
lines = fn'Opens the given file name in read mode and returns an iterator function that, each time it is called, returns a new line from the file. - (function)([file])',
open = fn'This function opens a file, in the mode specified in the string mode. It returns a new file handle, or, in case of errors, nil plus an error message. - (file,[errormsg])(filename,[mode])',
output = fn'Similar to io.input, but operates over the default output file. - ([file])([file])',
popen = fn'Starts program prog in a separated process and returns a file handle that you can use to read data from this program (if mode is "r", the default) or to write data to this program (if mode is "w"). - (file)([prog, [mode]])',
read = fn'Reads the file file, according to the given formats, which specify what to read. For each format, the function returns a string (or a number) with the characters read, or nil if it cannot read data with the specified format. When called without formats, it uses a default format that reads the entire next line (see below). - (string)(...)',
tmpfile = fn'Returns a handle for a temporary file. This file is opened in update mode and it is automatically removed when the program ends. - (file)()',
type = fn'Checks whether obj is a valid file handle. Returns the string "file" if obj is an open file handle, "closed file" if obj is a closed file handle, or nil if obj is not a file handle. - (string)(file)',
write = fn'Writes the value of each of its arguments to the file. The arguments must be strings or numbers. To write other values, use tostring or string.format before write. - (?)(...)',
seek = fn'Sets and gets the file position, measured from the beginning of the file, to the position given by offset plus a base specified by the string whence - (?)([whence] [, offset])',
setvbuf = fn'Sets the buffering mode for an output file. - (?)(mode [, size])',
}
},
os = {
type = "lib",
description = ' Operating System Facilities',
childs = {
clock = fn'Returns an approximation of the amount in seconds of CPU time used by the program. - (seconds)()',
date = fn'Returns a string or a table containing date and time, formatted according to the given string format. - (string)([format [, time]])',
difftime = fn'Returns the number of seconds from time t1 to time t2. In POSIX, Windows, and some other systems, this value is exactly t2-t1. - (time)(t2,t1)',
execute = fn'This function is equivalent to the C function system. It passes command to be executed by an operating system shell. It returns a status code, which is system-dependent. If command is absent, then it returns nonzero if a shell is available and zero otherwise. - (return)([cmd])',
exit = fn'Calls the C function exit, with an optional code, to terminate the host program. The default value for code is the success code. - ()([code])',
getenv = fn'Returns the value of the process environment variable varname, or nil if the variable is not defined. - ([string])(varname)',
remove = fn'Deletes the file or directory with the given name. Directories must be empty to be removed. If this function fails, it returns nil, plus a string describing the error. - (success,[error])(filename)',
rename = fn'Renames file or directory named oldname to newname. If this function fails, it returns nil, plus a string describing the error. - (success,[error])(oldname, newname)',
setlocale = fn'Sets the current locale of the program. locale is a string specifying a locale; category is an optional string describing which category to change: "all", "collate", "ctype", "monetary", "numeric", or "time"; the default category is "all". The function returns the name of the new locale, or nil if the request cannot be honored. - ([string])(locale [, category])',
time = fn'Returns the current time when called without arguments, or a time representing the date and time specified by the given table. This table must have fields year, month, and day, and may have fields hour, min, sec, and isdst (for a description of these fields, see the os.date function). - (time)([table])',
tmpname = fn'Returns a string with a file name that can be used for a temporary file. The file must be explicitly opened before its use and explicitly removed when no longer needed. - (string)()',
}
},
}
local function key (str)
api[str] = {type="keyword"}
return key
end
-- keywords - shouldn't be left out
key "local" "not" "if" "elseif" "else" "end" "do" "while" "repeat" "function" "until" "or"
"or" "and" "then" "true" "false" "return" "break" "in"
-- authors: Luxinia Dev (Eike Decker & Christoph Kubisch)
---------------------------------------------------------
-- function helpers
local function fn (description)
local description2,returns,args = description:match("(.+)%-%s*(%b())%s*(%b())")
if not description2 then
return {type="function",description=description,
returns="(?)"}
end
returns = returns:gsub("^%s+",""):gsub("%s+$","")
local ret = returns:sub(2,-2)
local vt = ret:match("^%[?string") and "string"
vt = vt or ret:match("^%[?table") and "table"
vt = vt or ret:match("^%[?file") and "io"
return {type="function",description=description2,
returns=returns, args = args, valuetype = vt}
end
local function val (description)
return {type="value",description = description}
end
-- docs
local api = {
table = {
description = "Table functions",
type = "lib",
childs = {
concat = fn "concatenates an array of elements - (string)(table,[sep])",
insert = fn "inserts an element into an array - ()(table,idx,element)",
remove = fn "removes an element from an array - (element)(table,idx)",
maxn = fn "Returns the largest positive numerical index of the given table, or zero if the table has no positive numerical indices. - (number)(table)",
sort = fn "Sorts table elements in a given order, in-place, from table[1] to table[n], where n is the length of the table. - ()(table,[comp])"
}
},
math = {
type = "lib",
description = "Math functions",
childs = {
abs = fn "Returns the absolute value of x. - (number)(number)",
acos = fn "Returns the arc cosine of x (in radians). - (number)(number)",
asin = fn "Returns the arc sine of x (in radians). - (number)(number)",
atan = fn "Returns the arc tangent of x (in radians). - (number)(number)",
atan2 = fn "Returns the arc tangent of x/y (in radians), but uses the signs of both parameters to find the quadrant of the result. (It also handles correctly the case of y being zero.) - (number)(number,number)",
ceil = fn "Returns the smallest integer larger than or equal to x. - (number)(number)",
cos = fn "Returns the cosine of x (assumed to be in radians).",
cosh = fn "Returns the hyperbolic cosine of x.",
deg = fn "Returns the angle x (given in radians) in degrees.",
exp = fn "Returns the the value ex.",
floor = fn "Returns the largest integer smaller than or equal to x.",
fmod = fn "Returns the remainder of the division of x by y.",
frexp = fn "Returns m and e such that x = m2e, e is an integer and the absolute value of m is in the range [0.5, 1) (or zero when x is zero).",
huge = val "The value HUGE_VAL, a value larger than or equal to any other numerical value.",
ldexp = fn "Returns m2e (e should be an integer).",
log = fn "Returns the natural logarithm of x.",
log10 = fn "Returns the base-10 logarithm of x.",
max = fn "Returns the maximum value among its arguments.",
min = fn "Returns the minimum value among its arguments.",
modf = fn "Returns two numbers, the integral part of x and the fractional part of x.",
pi = val "The value PI.",
pow = fn "Returns xy. (You can also use the expression x^y to compute this value.)",
rad = fn "Returns the angle x (given in degrees) in radians.",
random = fn "This function is an interface to the simple pseudo-random generator function rand provided by ANSI C. (No guarantees can be given for its statistical properties.) When called without arguments, returns a pseudo-random real number in the range [0,1). When called with a number m, math.random returns a pseudo-random integer in the range [1, m]. When called with two numbers m and n, math.random returns a pseudo-random integer in the range [m, n].",
randomseed = fn "Sets x as the \"seed\" for the pseudo-random generator: equal seeds produce equal sequences of numbers.",
sin = fn"Returns the sine of x (assumed to be in radians).",
sinh = fn"Returns the hyperbolic sine of x.",
sqrt = fn "Returns the square root of x. (You can also use the expression x^0.5 to compute this value.)",
tan = fn "Returns the tangent of x (assumed to be in radians).",
tanh = fn "Returns the hyperbolic tangent of x. "
}
},
pairs = fn "returns an iterator function for the given table - (function)(table)",
ipairs = fn "returns an iterator function for the given table - (function)(table)",
xpcall = fn "calls a function in protected mode - (boolean success, [error string / result])(called,errorfunc)",
pcall = fn "calls a function in protected mode - (boolean success, [error string / result])(called, args ...)",
print = fn "prints out the arguments - ()(...)",
assert = fn "error checking, if first arg is false, error message is thrown - (result)(compute,errormsg)",
collectgarbage = fn "garbage collector manipulation - (...)(...)",
dofile = fn "compile and execute a file - (...)(...)",
error = fn "raise an error - (...)(...)",
getfenv = fn "get the function environment for a function - (...)(...)",
getmetatable = fn "not yet - (...)(...)",
load = fn "not yet - (...)(...)",
loadfile = fn "not yet - (...)(...)",
loadstring = fn "not yet - (...)(...)",
next = fn "not yet - (...)(...)",
rawequal = fn "not yet - (...)(...)",
rawget = fn "not yet - (...)(...)",
rawset = fn "not yet - (...)(...)",
select = fn "not yet - (...)(...)",
setfenv = fn "not yet - (...)(...)",
setmetatable = fn "not yet - (...)(...)",
tonumber = fn "not yet - (number)(...)",
tostring = fn "not yet - (string)(...)",
type = fn "not yet - (string)(...)",
unpack = fn "not yet - (...)(...)",
module = fn "Creates a module. - (?)(name,...)",
require = fn "Loads the given module. - (?)(name)",
package = {
type = "table",
description = "package info",
childs = {
cpath = val "The path used by require to search for a C loader. ",
loaded = val "A table used by require to control which modules are already loaded.",
loadlib = fn "Dynamically links the host program with the C library libname. - (?)(libname, funcname)",
path = val "The path used by require to search for a Lua loader. ",
preload = val "A table to store loaders for specific modules (see require). ",
seeall = fn "Sets a metatable for module with its __index field referring to the global environment, so that this module inherits values from the global environment. To be used as an option to function module. - (?)(module)"
}
},
string = {
type = "lib",
description = "string lib",
childs = {
byte = fn "Returns the internal numerical codes of the characters s[i], s[i+1], ···, s[j]. The default value for i is 1; the default value for j is i. - (number)(string [, i [, j]])",
char = fn "Receives zero or more integers. Returns a string with length equal to the number of arguments, in which each character has the internal numerical code equal to its corresponding argument. - (string)(...)",
dump = fn "Returns a string containing a binary representation of the given function, so that a later loadstring on this string returns a copy of the function. function must be a Lua function without upvalues. - (string)(func)",
find = fn "Looks for the first match of pattern in the string s. If it finds a match, then find returns the indices of s where this occurrence starts and ends; otherwise, it returns nil. A third, optional numerical argument init specifies where to start the search; its default value is 1 and may be negative. A value of true as a fourth, optional argument plain turns off the pattern matching facilities, so the function does a plain \"find substring\" operation, with no characters in pattern being considered \"magic\". Note that if plain is given, then init must be given as well. - (number,number)(string, pattern [, init [, plain]])",
format = fn "Returns a formatted version of its variable number of arguments following the description given in its first argument (which must be a string). The format string follows the same rules as the printf family of standard C functions. The only differences are that the options/modifiers *, l, L, n, p, and h are not supported and that there is an extra option, q. The q option formats a string in a form suitable to be safely read back by the Lua interpreter: the string is written between double quotes, and all double quotes, newlines, embedded zeros, and backslashes in the string are correctly escaped when written. - (string)(formatstring, ···)",
gmatch = fn "Returns an iterator function that, each time it is called, returns the next captures from pattern over string s. - (func)(string, pattern)",
gsub = fn "Returns a copy of s in which all occurrences of the pattern have been replaced by a replacement string specified by repl, which may be a string, a table, or a function. gsub also returns, as its second value, the total number of substitutions made. - (string,number)(string, pattern, repl [, n])",
len = fn "Receives a string and returns its length. The empty string '' has length 0. Embedded zeros are counted, so 'a\\000bc\\000' has length 5. - (number)(string)",
lower = fn "Receives a string and returns a copy of this string with all uppercase letters changed to lowercase. All other characters are left unchanged. The definition of what an uppercase letter is depends on the current locale. - (string)(string)",
match = fn "Looks for the first match of pattern in the string s. If it finds one, then match returns the captures from the pattern; otherwise it returns nil. If pattern specifies no captures, then the whole match is returned. A third, optional numerical argument init specifies where to start the search; its default value is 1 and may be negative. - (string,...)(string, pattern [, init])",
rep = fn "Returns a string that is the concatenation of n copies of the string s. - (string)(string s, n)",
reverse = fn "Returns a string that is the string s reversed. - (string)(string)",
sub = fn "Returns the substring of s that starts at i and continues until j; i and j may be negative. If j is absent, then it is assumed to be equal to -1 (which is the same as the string length). In particular, the call string.sub(s,1,j) returns a prefix of s with length j, and string.sub(s, -i) returns a suffix of s with length i. - (string)(string, i [, j])",
upper = fn "Receives a string and returns a copy of this string with all lowercase letters changed to uppercase. All other characters are left unchanged. The definition of what a lowercase letter is depends on the current locale. - (string)(string)",
}
},
coroutine = {
type = "lib",
description = "Lua supports coroutines, also called collaborative multithreading. A coroutine in Lua represents an independent thread of execution. Unlike threads in multithread systems, however, a coroutine only suspends its execution by explicitly calling a yield function.",
childs = {
create = fn 'Creates a new coroutine, with body f. f must be a Lua function. Returns this new coroutine, an object with type "thread". - (thread)(function)',
resume = fn 'Starts or continues the execution of coroutine co. The first time you resume a coroutine, it starts running its body. The values val1, ··· are passed as the arguments to the body function. If the coroutine has yielded, resume restarts it; the values val1, ··· are passed as the results from the yield. - (boolean success, ...)(coroutine,...)',
running = fn 'Returns the running coroutine, or nil when called by the main thread. - ([thread])()',
status = fn 'Returns the status of coroutine co, as a string: "running", if the coroutine is running (that is, it called status); "suspended", if the coroutine is suspended in a call to yield, or if it has not started running yet; "normal" if the coroutine is active but not running (that is, it has resumed another coroutine); and "dead" if the coroutine has finished its body function, or if it has stopped with an error. - (status)(coroutine)',
wrap = fn 'Creates a new coroutine, with body f. f must be a Lua function. Returns a function that resumes the coroutine each time it is called. Any arguments passed to the function behave as the extra arguments to resume. Returns the same values returned by resume, except the first boolean. In case of error, propagates the error. - (function)(function)',
yield = fn 'Suspends the execution of the calling coroutine. The coroutine cannot be running a C function, a metamethod, or an iterator. Any arguments to yield are passed as extra results to resume. - (...)(...)'
}
},
io = {
type = "lib",
description = "The I/O library provides two different styles for file manipulation. The first one uses implicit file descriptors; that is, there are operations to set a default input file and a default output file, and all input/output operations are over these default files. The second style uses explicit file descriptors. ",
childs = {
close = fn'Equivalent to file:close(). Without a file, closes the default output file. - ()([file])',
flush = fn'Equivalent to file:flush over the default output file. - ()([file])',
input = fn'When called with a file name, it opens the named file (in text mode), and sets its handle as the default input file. When called with a file handle, it simply sets this file handle as the default input file. When called without parameters, it returns the current default input file. - ([in])([file])',
lines = fn'Opens the given file name in read mode and returns an iterator function that, each time it is called, returns a new line from the file. - (function)([file])',
open = fn'This function opens a file, in the mode specified in the string mode. It returns a new file handle, or, in case of errors, nil plus an error message. - (file,[errormsg])(filename,[mode])',
output = fn'Similar to io.input, but operates over the default output file. - ([file])([file])',
popen = fn'Starts program prog in a separated process and returns a file handle that you can use to read data from this program (if mode is "r", the default) or to write data to this program (if mode is "w"). - (file)([prog, [mode]])',
read = fn'Reads the file file, according to the given formats, which specify what to read. For each format, the function returns a string (or a number) with the characters read, or nil if it cannot read data with the specified format. When called without formats, it uses a default format that reads the entire next line (see below). - (string)(...)',
tmpfile = fn'Returns a handle for a temporary file. This file is opened in update mode and it is automatically removed when the program ends. - (file)()',
type = fn'Checks whether obj is a valid file handle. Returns the string "file" if obj is an open file handle, "closed file" if obj is a closed file handle, or nil if obj is not a file handle. - (string)(file)',
write = fn'Writes the value of each of its arguments to the file. The arguments must be strings or numbers. To write other values, use tostring or string.format before write. - (?)(...)',
seek = fn'Sets and gets the file position, measured from the beginning of the file, to the position given by offset plus a base specified by the string whence - (?)([whence] [, offset])',
setvbuf = fn'Sets the buffering mode for an output file. - (?)(mode [, size])',
}
},
os = {
type = "lib",
description = ' Operating System Facilities',
childs = {
clock = fn'Returns an approximation of the amount in seconds of CPU time used by the program. - (seconds)()',
date = fn'Returns a string or a table containing date and time, formatted according to the given string format. - (string)([format [, time]])',
difftime = fn'Returns the number of seconds from time t1 to time t2. In POSIX, Windows, and some other systems, this value is exactly t2-t1. - (time)(t2,t1)',
execute = fn'This function is equivalent to the C function system. It passes command to be executed by an operating system shell. It returns a status code, which is system-dependent. If command is absent, then it returns nonzero if a shell is available and zero otherwise. - (return)([cmd])',
exit = fn'Calls the C function exit, with an optional code, to terminate the host program. The default value for code is the success code. - ()([code])',
getenv = fn'Returns the value of the process environment variable varname, or nil if the variable is not defined. - ([string])(varname)',
remove = fn'Deletes the file or directory with the given name. Directories must be empty to be removed. If this function fails, it returns nil, plus a string describing the error. - (success,[error])(filename)',
rename = fn'Renames file or directory named oldname to newname. If this function fails, it returns nil, plus a string describing the error. - (success,[error])(oldname, newname)',
setlocale = fn'Sets the current locale of the program. locale is a string specifying a locale; category is an optional string describing which category to change: "all", "collate", "ctype", "monetary", "numeric", or "time"; the default category is "all". The function returns the name of the new locale, or nil if the request cannot be honored. - ([string])(locale [, category])',
time = fn'Returns the current time when called without arguments, or a time representing the date and time specified by the given table. This table must have fields year, month, and day, and may have fields hour, min, sec, and isdst (for a description of these fields, see the os.date function). - (time)([table])',
tmpname = fn'Returns a string with a file name that can be used for a temporary file. The file must be explicitly opened before its use and explicitly removed when no longer needed. - (string)()',
}
},
}
local function key (str)
api[str] = {type="keyword"}
return key
end
-- keywords - shouldn't be left out
key "local" "not" "if" "elseif" "else" "end" "do" "while" "repeat" "function" "until" "or"
"or" "and" "then" "true" "false" "return" "break" "in"
return api

930
api/lua/glfw.lua Normal file
View File

@@ -0,0 +1,930 @@
--[[// glfw | GLFW window manager
enum {
/*************************************************************************
* GLFW version
*************************************************************************/
GLFW_VERSION_MAJOR =2,
GLFW_VERSION_MINOR =7,
GLFW_VERSION_REVISION =2,
/*************************************************************************
* Input handling definitions
*************************************************************************/
/* Key and button state/action definitions */
GLFW_RELEASE =0,
GLFW_PRESS =1,
GLFW_TRUE = 1,
GLFW_FALSE = 0,
/* Keyboard key definitions: 8-bit ISO-8859-1 (Latin 1) encoding is used
* for printable keys (such as A-Z, 0-9 etc), and values above 256
* represent special (non-printable) keys (e.g. F1, Page Up etc).
*/
GLFW_KEY_UNKNOWN =-1,
GLFW_KEY_SPACE =32,
GLFW_KEY_APOSTROPHE = 39,
GLFW_KEY_COMMA = 44,
GLFW_KEY_MINUS = 45,
GLFW_KEY_PERIOD = 46,
GLFW_KEY_SLASH = 47,
GLFW_KEY_0 = 48,
GLFW_KEY_1 = 49,
GLFW_KEY_2 = 50,
GLFW_KEY_3 = 51,
GLFW_KEY_4 = 52,
GLFW_KEY_5 = 53,
GLFW_KEY_6 = 54,
GLFW_KEY_7 = 55,
GLFW_KEY_8 = 56,
GLFW_KEY_9 = 57,
GLFW_KEY_SEMICOLON = 59,
GLFW_KEY_EQUAL = 61,
GLFW_KEY_A = 65,
GLFW_KEY_B = 66,
GLFW_KEY_C = 67,
GLFW_KEY_D = 68,
GLFW_KEY_E = 69,
GLFW_KEY_F = 70,
GLFW_KEY_G = 71,
GLFW_KEY_H = 72,
GLFW_KEY_I = 73,
GLFW_KEY_J = 74,
GLFW_KEY_K = 75,
GLFW_KEY_L = 76,
GLFW_KEY_M = 77,
GLFW_KEY_N = 78,
GLFW_KEY_O = 79,
GLFW_KEY_P = 80,
GLFW_KEY_Q = 81,
GLFW_KEY_R = 82,
GLFW_KEY_S = 83,
GLFW_KEY_T = 84,
GLFW_KEY_U = 85,
GLFW_KEY_V = 86,
GLFW_KEY_W = 87,
GLFW_KEY_X = 88,
GLFW_KEY_Y = 89,
GLFW_KEY_Z = 90,
GLFW_KEY_LEFT_BRACKET = 91,
GLFW_KEY_BACKSLASH = 92,
GLFW_KEY_RIGHT_BRACKET = 93,
GLFW_KEY_GRAVE_ACCENT = 96,
GLFW_KEY_WORLD_1 = 161,
GLFW_KEY_WORLD_2 = 162,
GLFW_KEY_SPECIAL =256,
GLFW_KEY_ESC =(GLFW_KEY_SPECIAL+1),
GLFW_KEY_F1 =(GLFW_KEY_SPECIAL+2),
GLFW_KEY_F2 =(GLFW_KEY_SPECIAL+3),
GLFW_KEY_F3 =(GLFW_KEY_SPECIAL+4),
GLFW_KEY_F4 =(GLFW_KEY_SPECIAL+5),
GLFW_KEY_F5 =(GLFW_KEY_SPECIAL+6),
GLFW_KEY_F6 =(GLFW_KEY_SPECIAL+7),
GLFW_KEY_F7 =(GLFW_KEY_SPECIAL+8),
GLFW_KEY_F8 =(GLFW_KEY_SPECIAL+9),
GLFW_KEY_F9 =(GLFW_KEY_SPECIAL+10),
GLFW_KEY_F10 =(GLFW_KEY_SPECIAL+11),
GLFW_KEY_F11 =(GLFW_KEY_SPECIAL+12),
GLFW_KEY_F12 =(GLFW_KEY_SPECIAL+13),
GLFW_KEY_F13 =(GLFW_KEY_SPECIAL+14),
GLFW_KEY_F14 =(GLFW_KEY_SPECIAL+15),
GLFW_KEY_F15 =(GLFW_KEY_SPECIAL+16),
GLFW_KEY_F16 =(GLFW_KEY_SPECIAL+17),
GLFW_KEY_F17 =(GLFW_KEY_SPECIAL+18),
GLFW_KEY_F18 =(GLFW_KEY_SPECIAL+19),
GLFW_KEY_F19 =(GLFW_KEY_SPECIAL+20),
GLFW_KEY_F20 =(GLFW_KEY_SPECIAL+21),
GLFW_KEY_F21 =(GLFW_KEY_SPECIAL+22),
GLFW_KEY_F22 =(GLFW_KEY_SPECIAL+23),
GLFW_KEY_F23 =(GLFW_KEY_SPECIAL+24),
GLFW_KEY_F24 =(GLFW_KEY_SPECIAL+25),
GLFW_KEY_F25 =(GLFW_KEY_SPECIAL+26),
GLFW_KEY_UP =(GLFW_KEY_SPECIAL+27),
GLFW_KEY_DOWN =(GLFW_KEY_SPECIAL+28),
GLFW_KEY_LEFT =(GLFW_KEY_SPECIAL+29),
GLFW_KEY_RIGHT =(GLFW_KEY_SPECIAL+30),
GLFW_KEY_LSHIFT =(GLFW_KEY_SPECIAL+31),
GLFW_KEY_RSHIFT =(GLFW_KEY_SPECIAL+32),
GLFW_KEY_LCTRL =(GLFW_KEY_SPECIAL+33),
GLFW_KEY_RCTRL =(GLFW_KEY_SPECIAL+34),
GLFW_KEY_LALT =(GLFW_KEY_SPECIAL+35),
GLFW_KEY_RALT =(GLFW_KEY_SPECIAL+36),
GLFW_KEY_TAB =(GLFW_KEY_SPECIAL+37),
GLFW_KEY_ENTER =(GLFW_KEY_SPECIAL+38),
GLFW_KEY_BACKSPACE =(GLFW_KEY_SPECIAL+39),
GLFW_KEY_INSERT =(GLFW_KEY_SPECIAL+40),
GLFW_KEY_DEL =(GLFW_KEY_SPECIAL+41),
GLFW_KEY_PAGEUP =(GLFW_KEY_SPECIAL+42),
GLFW_KEY_PAGEDOWN =(GLFW_KEY_SPECIAL+43),
GLFW_KEY_HOME =(GLFW_KEY_SPECIAL+44),
GLFW_KEY_END =(GLFW_KEY_SPECIAL+45),
GLFW_KEY_KP_0 =(GLFW_KEY_SPECIAL+46),
GLFW_KEY_KP_1 =(GLFW_KEY_SPECIAL+47),
GLFW_KEY_KP_2 =(GLFW_KEY_SPECIAL+48),
GLFW_KEY_KP_3 =(GLFW_KEY_SPECIAL+49),
GLFW_KEY_KP_4 =(GLFW_KEY_SPECIAL+50),
GLFW_KEY_KP_5 =(GLFW_KEY_SPECIAL+51),
GLFW_KEY_KP_6 =(GLFW_KEY_SPECIAL+52),
GLFW_KEY_KP_7 =(GLFW_KEY_SPECIAL+53),
GLFW_KEY_KP_8 =(GLFW_KEY_SPECIAL+54),
GLFW_KEY_KP_9 =(GLFW_KEY_SPECIAL+55),
GLFW_KEY_KP_DIVIDE =(GLFW_KEY_SPECIAL+56),
GLFW_KEY_KP_MULTIPLY =(GLFW_KEY_SPECIAL+57),
GLFW_KEY_KP_SUBTRACT =(GLFW_KEY_SPECIAL+58),
GLFW_KEY_KP_ADD =(GLFW_KEY_SPECIAL+59),
GLFW_KEY_KP_DECIMAL =(GLFW_KEY_SPECIAL+60),
GLFW_KEY_KP_EQUAL =(GLFW_KEY_SPECIAL+61),
GLFW_KEY_KP_ENTER =(GLFW_KEY_SPECIAL+62),
GLFW_KEY_KP_NUM_LOCK =(GLFW_KEY_SPECIAL+63),
GLFW_KEY_CAPS_LOCK =(GLFW_KEY_SPECIAL+64),
GLFW_KEY_SCROLL_LOCK =(GLFW_KEY_SPECIAL+65),
GLFW_KEY_PAUSE =(GLFW_KEY_SPECIAL+66),
GLFW_KEY_LSUPER =(GLFW_KEY_SPECIAL+67),
GLFW_KEY_RSUPER =(GLFW_KEY_SPECIAL+68),
GLFW_KEY_MENU =(GLFW_KEY_SPECIAL+69),
GLFW_KEY_LAST =GLFW_KEY_MENU,
/* Mouse button definitions */
GLFW_MOUSE_BUTTON_1 =0,
GLFW_MOUSE_BUTTON_2 =1,
GLFW_MOUSE_BUTTON_3 =2,
GLFW_MOUSE_BUTTON_4 =3,
GLFW_MOUSE_BUTTON_5 =4,
GLFW_MOUSE_BUTTON_6 =5,
GLFW_MOUSE_BUTTON_7 =6,
GLFW_MOUSE_BUTTON_8 =7,
GLFW_MOUSE_BUTTON_LAST =GLFW_MOUSE_BUTTON_8,
/* Mouse button aliases */
GLFW_MOUSE_BUTTON_LEFT =GLFW_MOUSE_BUTTON_1,
GLFW_MOUSE_BUTTON_RIGHT =GLFW_MOUSE_BUTTON_2,
GLFW_MOUSE_BUTTON_MIDDLE =GLFW_MOUSE_BUTTON_3,
/* Joystick identifiers */
GLFW_JOYSTICK_1 =0,
GLFW_JOYSTICK_2 =1,
GLFW_JOYSTICK_3 =2,
GLFW_JOYSTICK_4 =3,
GLFW_JOYSTICK_5 =4,
GLFW_JOYSTICK_6 =5,
GLFW_JOYSTICK_7 =6,
GLFW_JOYSTICK_8 =7,
GLFW_JOYSTICK_9 =8,
GLFW_JOYSTICK_10 =9,
GLFW_JOYSTICK_11 =10,
GLFW_JOYSTICK_12 =11,
GLFW_JOYSTICK_13 =12,
GLFW_JOYSTICK_14 =13,
GLFW_JOYSTICK_15 =14,
GLFW_JOYSTICK_16 =15,
GLFW_JOYSTICK_LAST =GLFW_JOYSTICK_16,
/*************************************************************************
* Other definitions
*************************************************************************/
/* glfwOpenWindow modes */
GLFW_WINDOW =0x00010001,
GLFW_FULLSCREEN =0x00010002,
/* glfwGetWindowParam tokens */
GLFW_OPENED =0x00020001,
GLFW_ACTIVE =0x00020002,
GLFW_ICONIFIED =0x00020003,
GLFW_ACCELERATED =0x00020004,
GLFW_RED_BITS =0x00020005,
GLFW_GREEN_BITS =0x00020006,
GLFW_BLUE_BITS =0x00020007,
GLFW_ALPHA_BITS =0x00020008,
GLFW_DEPTH_BITS =0x00020009,
GLFW_STENCIL_BITS =0x0002000A,
/* The following constants are used for both glfwGetWindowParam
* and glfwOpenWindowHint
*/
GLFW_REFRESH_RATE =0x0002000B,
GLFW_ACCUM_RED_BITS =0x0002000C,
GLFW_ACCUM_GREEN_BITS =0x0002000D,
GLFW_ACCUM_BLUE_BITS =0x0002000E,
GLFW_ACCUM_ALPHA_BITS =0x0002000F,
GLFW_AUX_BUFFERS =0x00020010,
GLFW_STEREO =0x00020011,
GLFW_WINDOW_NO_RESIZE =0x00020012,
GLFW_FSAA_SAMPLES =0x00020013,
GLFW_OPENGL_VERSION_MAJOR =0x00020014,
GLFW_OPENGL_VERSION_MINOR =0x00020015,
GLFW_OPENGL_FORWARD_COMPAT =0x00020016,
GLFW_OPENGL_DEBUG_CONTEXT =0x00020017,
GLFW_OPENGL_PROFILE =0x00020018,
/* GLFW_OPENGL_PROFILE tokens */
GLFW_OPENGL_CORE_PROFILE =0x00050001,
GLFW_OPENGL_COMPAT_PROFILE =0x00050002,
/* glfwEnable/glfwDisable tokens */
GLFW_MOUSE_CURSOR =0x00030001,
GLFW_STICKY_KEYS =0x00030002,
GLFW_STICKY_MOUSE_BUTTONS =0x00030003,
GLFW_SYSTEM_KEYS =0x00030004,
GLFW_KEY_REPEAT =0x00030005,
GLFW_AUTO_POLL_EVENTS =0x00030006,
/* glfwWaitThread wait modes */
GLFW_WAIT =0x00040001,
GLFW_NOWAIT =0x00040002,
/* glfwGetJoystickParam tokens */
GLFW_PRESENT =0x00050001,
GLFW_AXES =0x00050002,
GLFW_BUTTONS =0x00050003,
/* glfwReadImage/glfwLoadTexture2D flags */
GLFW_NO_RESCALE_BIT =0x00000001 /* Only for glfwReadImage */,
GLFW_ORIGIN_UL_BIT =0x00000002,
GLFW_BUILD_MIPMAPS_BIT =0x00000004 /* Only for glfwLoadTexture2D */,
GLFW_ALPHA_MAP_BIT =0x00000008,
/* Time spans longer than this (seconds) are considered to be infinity */
};
const float GLFW_INFINITY =100000.0;
/* The video mode structure used by glfwGetVideoModes() */
typedef struct {
int Width, Height;
int RedBits, BlueBits, GreenBits;
} GLFWvidmode;
/* Image/texture information */
typedef struct {
int Width, Height;
int Format;
int BytesPerPixel;
unsigned char *Data;
} GLFWimage;
/* Thread ID */
typedef int GLFWthread;
/* Mutex object */
typedef void * GLFWmutex;
/* Condition variable object */
typedef void * GLFWcond;
/* Function pointer types */
typedef void (GLFWCALL * GLFWwindowsizefun)(int,int);
typedef int (GLFWCALL * GLFWwindowclosefun)(void);
typedef void (GLFWCALL * GLFWwindowrefreshfun)(void);
typedef void (GLFWCALL * GLFWmousebuttonfun)(int,int);
typedef void (GLFWCALL * GLFWmouseposfun)(int,int);
typedef void (GLFWCALL * GLFWmousewheelfun)(int);
typedef void (GLFWCALL * GLFWkeyfun)(int,int);
typedef void (GLFWCALL * GLFWcharfun)(int,int);
typedef void (GLFWCALL * GLFWthreadfun)(void *);
/*************************************************************************
* Prototypes
*************************************************************************/
/* GLFW initialization, termination and version querying */
int glfwInit( void );
void glfwTerminate( void );
void glfwGetVersion( int *major, int *minor, int *rev );
/* Window handling */
int glfwOpenWindow( int width, int height, int redbits, int greenbits, int bluebits, int alphabits, int depthbits, int stencilbits, int mode );
void glfwOpenWindowHint( int target, int hint );
void glfwCloseWindow( void );
void glfwSetWindowTitle( const char *title );
void glfwGetWindowSize( int *width, int *height );
void glfwSetWindowSize( int width, int height );
void glfwSetWindowPos( int x, int y );
void glfwIconifyWindow( void );
void glfwRestoreWindow( void );
void glfwSwapBuffers( void );
void glfwSwapInterval( int interval );
int glfwGetWindowParam( int param );
void glfwSetWindowSizeCallback( GLFWwindowsizefun cbfun );
void glfwSetWindowCloseCallback( GLFWwindowclosefun cbfun );
void glfwSetWindowRefreshCallback( GLFWwindowrefreshfun cbfun );
/* Video mode functions */
int glfwGetVideoModes( GLFWvidmode *list, int maxcount );
void glfwGetDesktopMode( GLFWvidmode *mode );
/* Input handling */
void glfwPollEvents( void );
void glfwWaitEvents( void );
int glfwGetKey( int key );
int glfwGetMouseButton( int button );
void glfwGetMousePos( int *xpos, int *ypos );
void glfwSetMousePos( int xpos, int ypos );
int glfwGetMouseWheel( void );
void glfwSetMouseWheel( int pos );
void glfwSetKeyCallback( GLFWkeyfun cbfun );
void glfwSetCharCallback( GLFWcharfun cbfun );
void glfwSetMouseButtonCallback( GLFWmousebuttonfun cbfun );
void glfwSetMousePosCallback( GLFWmouseposfun cbfun );
void glfwSetMouseWheelCallback( GLFWmousewheelfun cbfun );
/* Joystick input */
int glfwGetJoystickParam( int joy, int param );
int glfwGetJoystickPos( int joy, float *pos, int numaxes );
int glfwGetJoystickButtons( int joy, unsigned char *buttons, int numbuttons );
/* Time */
double glfwGetTime( void );
void glfwSetTime( double time );
void glfwSleep( double time );
/* Extension support */
int glfwExtensionSupported( const char *extension );
void* glfwGetProcAddress( const char *procname );
void glfwGetGLVersion( int *major, int *minor, int *rev );
/* Threading support */
GLFWthread glfwCreateThread( GLFWthreadfun fun, void *arg );
void glfwDestroyThread( GLFWthread ID );
int glfwWaitThread( GLFWthread ID, int waitmode );
GLFWthread glfwGetThreadID( void );
GLFWmutex glfwCreateMutex( void );
void glfwDestroyMutex( GLFWmutex mutex );
void glfwLockMutex( GLFWmutex mutex );
void glfwUnlockMutex( GLFWmutex mutex );
GLFWcond glfwCreateCond( void );
void glfwDestroyCond( GLFWcond cond );
void glfwWaitCond( GLFWcond cond, GLFWmutex mutex, double timeout );
void glfwSignalCond( GLFWcond cond );
void glfwBroadcastCond( GLFWcond cond );
int glfwGetNumberOfProcessors( void );
/* Enable/disable functions */
void glfwEnable( int token );
void glfwDisable( int token );
/* Image/texture I/O support */
int glfwReadImage( const char *name, GLFWimage *img, int flags );
int glfwReadMemoryImage( const void *data, long size, GLFWimage *img, int flags );
void glfwFreeImage( GLFWimage *img );
int glfwLoadTexture2D( const char *name, int flags );
int glfwLoadMemoryTexture2D( const void *data, long size, int flags );
int glfwLoadTextureImage2D( GLFWimage *img, int flags );
]]
--auto-generated api from ffi headers
local api =
{
["GLFW_VERSION_MAJOR"] = { type ='value', },
["GLFW_VERSION_MINOR"] = { type ='value', },
["GLFW_VERSION_REVISION"] = { type ='value', },
["GLFW_RELEASE"] = { type ='value', },
["GLFW_PRESS"] = { type ='value', },
["GLFW_KEY_UNKNOWN"] = { type ='value', },
["GLFW_KEY_SPACE"] = { type ='value', },
["GLFW_KEY_APOSTROPHE"] = { type ='value', },
["GLFW_KEY_COMMA"] = { type ='value', },
["GLFW_KEY_MINUS"] = { type ='value', },
["GLFW_KEY_PERIOD"] = { type ='value', },
["GLFW_KEY_SLASH"] = { type ='value', },
["GLFW_KEY_0"] = { type ='value', },
["GLFW_KEY_1"] = { type ='value', },
["GLFW_KEY_2"] = { type ='value', },
["GLFW_KEY_3"] = { type ='value', },
["GLFW_KEY_4"] = { type ='value', },
["GLFW_KEY_5"] = { type ='value', },
["GLFW_KEY_6"] = { type ='value', },
["GLFW_KEY_7"] = { type ='value', },
["GLFW_KEY_8"] = { type ='value', },
["GLFW_KEY_9"] = { type ='value', },
["GLFW_KEY_SEMICOLON"] = { type ='value', },
["GLFW_KEY_EQUAL"] = { type ='value', },
["GLFW_KEY_A"] = { type ='value', },
["GLFW_KEY_B"] = { type ='value', },
["GLFW_KEY_C"] = { type ='value', },
["GLFW_KEY_D"] = { type ='value', },
["GLFW_KEY_E"] = { type ='value', },
["GLFW_KEY_F"] = { type ='value', },
["GLFW_KEY_G"] = { type ='value', },
["GLFW_KEY_H"] = { type ='value', },
["GLFW_KEY_I"] = { type ='value', },
["GLFW_KEY_J"] = { type ='value', },
["GLFW_KEY_K"] = { type ='value', },
["GLFW_KEY_L"] = { type ='value', },
["GLFW_KEY_M"] = { type ='value', },
["GLFW_KEY_N"] = { type ='value', },
["GLFW_KEY_O"] = { type ='value', },
["GLFW_KEY_P"] = { type ='value', },
["GLFW_KEY_Q"] = { type ='value', },
["GLFW_KEY_R"] = { type ='value', },
["GLFW_KEY_S"] = { type ='value', },
["GLFW_KEY_T"] = { type ='value', },
["GLFW_KEY_U"] = { type ='value', },
["GLFW_KEY_V"] = { type ='value', },
["GLFW_KEY_W"] = { type ='value', },
["GLFW_KEY_X"] = { type ='value', },
["GLFW_KEY_Y"] = { type ='value', },
["GLFW_KEY_Z"] = { type ='value', },
["GLFW_KEY_LEFT_BRACKET"] = { type ='value', },
["GLFW_KEY_BACKSLASH"] = { type ='value', },
["GLFW_KEY_RIGHT_BRACKET"] = { type ='value', },
["GLFW_KEY_GRAVE_ACCENT"] = { type ='value', },
["GLFW_KEY_WORLD_1"] = { type ='value', },
["GLFW_KEY_WORLD_2"] = { type ='value', },
["GLFW_KEY_SPECIAL"] = { type ='value', },
["GLFW_KEY_ESC"] = { type ='value', },
["GLFW_KEY_F1"] = { type ='value', },
["GLFW_KEY_F2"] = { type ='value', },
["GLFW_KEY_F3"] = { type ='value', },
["GLFW_KEY_F4"] = { type ='value', },
["GLFW_KEY_F5"] = { type ='value', },
["GLFW_KEY_F6"] = { type ='value', },
["GLFW_KEY_F7"] = { type ='value', },
["GLFW_KEY_F8"] = { type ='value', },
["GLFW_KEY_F9"] = { type ='value', },
["GLFW_KEY_F10"] = { type ='value', },
["GLFW_KEY_F11"] = { type ='value', },
["GLFW_KEY_F12"] = { type ='value', },
["GLFW_KEY_F13"] = { type ='value', },
["GLFW_KEY_F14"] = { type ='value', },
["GLFW_KEY_F15"] = { type ='value', },
["GLFW_KEY_F16"] = { type ='value', },
["GLFW_KEY_F17"] = { type ='value', },
["GLFW_KEY_F18"] = { type ='value', },
["GLFW_KEY_F19"] = { type ='value', },
["GLFW_KEY_F20"] = { type ='value', },
["GLFW_KEY_F21"] = { type ='value', },
["GLFW_KEY_F22"] = { type ='value', },
["GLFW_KEY_F23"] = { type ='value', },
["GLFW_KEY_F24"] = { type ='value', },
["GLFW_KEY_F25"] = { type ='value', },
["GLFW_KEY_UP"] = { type ='value', },
["GLFW_KEY_DOWN"] = { type ='value', },
["GLFW_KEY_LEFT"] = { type ='value', },
["GLFW_KEY_RIGHT"] = { type ='value', },
["GLFW_KEY_LSHIFT"] = { type ='value', },
["GLFW_KEY_RSHIFT"] = { type ='value', },
["GLFW_KEY_LCTRL"] = { type ='value', },
["GLFW_KEY_RCTRL"] = { type ='value', },
["GLFW_KEY_LALT"] = { type ='value', },
["GLFW_KEY_RALT"] = { type ='value', },
["GLFW_KEY_TAB"] = { type ='value', },
["GLFW_KEY_ENTER"] = { type ='value', },
["GLFW_KEY_BACKSPACE"] = { type ='value', },
["GLFW_KEY_INSERT"] = { type ='value', },
["GLFW_KEY_DEL"] = { type ='value', },
["GLFW_KEY_PAGEUP"] = { type ='value', },
["GLFW_KEY_PAGEDOWN"] = { type ='value', },
["GLFW_KEY_HOME"] = { type ='value', },
["GLFW_KEY_END"] = { type ='value', },
["GLFW_KEY_KP_0"] = { type ='value', },
["GLFW_KEY_KP_1"] = { type ='value', },
["GLFW_KEY_KP_2"] = { type ='value', },
["GLFW_KEY_KP_3"] = { type ='value', },
["GLFW_KEY_KP_4"] = { type ='value', },
["GLFW_KEY_KP_5"] = { type ='value', },
["GLFW_KEY_KP_6"] = { type ='value', },
["GLFW_KEY_KP_7"] = { type ='value', },
["GLFW_KEY_KP_8"] = { type ='value', },
["GLFW_KEY_KP_9"] = { type ='value', },
["GLFW_KEY_KP_DIVIDE"] = { type ='value', },
["GLFW_KEY_KP_MULTIPLY"] = { type ='value', },
["GLFW_KEY_KP_SUBTRACT"] = { type ='value', },
["GLFW_KEY_KP_ADD"] = { type ='value', },
["GLFW_KEY_KP_DECIMAL"] = { type ='value', },
["GLFW_KEY_KP_EQUAL"] = { type ='value', },
["GLFW_KEY_KP_ENTER"] = { type ='value', },
["GLFW_KEY_KP_NUM_LOCK"] = { type ='value', },
["GLFW_KEY_CAPS_LOCK"] = { type ='value', },
["GLFW_KEY_SCROLL_LOCK"] = { type ='value', },
["GLFW_KEY_PAUSE"] = { type ='value', },
["GLFW_KEY_LSUPER"] = { type ='value', },
["GLFW_KEY_RSUPER"] = { type ='value', },
["GLFW_KEY_MENU"] = { type ='value', },
["GLFW_KEY_LAST"] = { type ='value', },
["GLFW_MOUSE_BUTTON_1"] = { type ='value', },
["GLFW_MOUSE_BUTTON_2"] = { type ='value', },
["GLFW_MOUSE_BUTTON_3"] = { type ='value', },
["GLFW_MOUSE_BUTTON_4"] = { type ='value', },
["GLFW_MOUSE_BUTTON_5"] = { type ='value', },
["GLFW_MOUSE_BUTTON_6"] = { type ='value', },
["GLFW_MOUSE_BUTTON_7"] = { type ='value', },
["GLFW_MOUSE_BUTTON_8"] = { type ='value', },
["GLFW_MOUSE_BUTTON_LAST"] = { type ='value', },
["GLFW_MOUSE_BUTTON_LEFT"] = { type ='value', },
["GLFW_MOUSE_BUTTON_RIGHT"] = { type ='value', },
["GLFW_MOUSE_BUTTON_MIDDLE"] = { type ='value', },
["GLFW_JOYSTICK_1"] = { type ='value', },
["GLFW_JOYSTICK_2"] = { type ='value', },
["GLFW_JOYSTICK_3"] = { type ='value', },
["GLFW_JOYSTICK_4"] = { type ='value', },
["GLFW_JOYSTICK_5"] = { type ='value', },
["GLFW_JOYSTICK_6"] = { type ='value', },
["GLFW_JOYSTICK_7"] = { type ='value', },
["GLFW_JOYSTICK_8"] = { type ='value', },
["GLFW_JOYSTICK_9"] = { type ='value', },
["GLFW_JOYSTICK_10"] = { type ='value', },
["GLFW_JOYSTICK_11"] = { type ='value', },
["GLFW_JOYSTICK_12"] = { type ='value', },
["GLFW_JOYSTICK_13"] = { type ='value', },
["GLFW_JOYSTICK_14"] = { type ='value', },
["GLFW_JOYSTICK_15"] = { type ='value', },
["GLFW_JOYSTICK_16"] = { type ='value', },
["GLFW_JOYSTICK_LAST"] = { type ='value', },
["GLFW_WINDOW"] = { type ='value', },
["GLFW_FULLSCREEN"] = { type ='value', },
["GLFW_OPENED"] = { type ='value', },
["GLFW_ACTIVE"] = { type ='value', },
["GLFW_ICONIFIED"] = { type ='value', },
["GLFW_ACCELERATED"] = { type ='value', },
["GLFW_RED_BITS"] = { type ='value', },
["GLFW_GREEN_BITS"] = { type ='value', },
["GLFW_BLUE_BITS"] = { type ='value', },
["GLFW_ALPHA_BITS"] = { type ='value', },
["GLFW_DEPTH_BITS"] = { type ='value', },
["GLFW_STENCIL_BITS"] = { type ='value', },
["GLFW_REFRESH_RATE"] = { type ='value', },
["GLFW_ACCUM_RED_BITS"] = { type ='value', },
["GLFW_ACCUM_GREEN_BITS"] = { type ='value', },
["GLFW_ACCUM_BLUE_BITS"] = { type ='value', },
["GLFW_ACCUM_ALPHA_BITS"] = { type ='value', },
["GLFW_AUX_BUFFERS"] = { type ='value', },
["GLFW_STEREO"] = { type ='value', },
["GLFW_WINDOW_NO_RESIZE"] = { type ='value', },
["GLFW_FSAA_SAMPLES"] = { type ='value', },
["GLFW_OPENGL_VERSION_MAJOR"] = { type ='value', },
["GLFW_OPENGL_VERSION_MINOR"] = { type ='value', },
["GLFW_OPENGL_FORWARD_COMPAT"] = { type ='value', },
["GLFW_OPENGL_DEBUG_CONTEXT"] = { type ='value', },
["GLFW_OPENGL_PROFILE"] = { type ='value', },
["GLFW_OPENGL_CORE_PROFILE"] = { type ='value', },
["GLFW_OPENGL_COMPAT_PROFILE"] = { type ='value', },
["GLFW_MOUSE_CURSOR"] = { type ='value', },
["GLFW_STICKY_KEYS"] = { type ='value', },
["GLFW_STICKY_MOUSE_BUTTONS"] = { type ='value', },
["GLFW_SYSTEM_KEYS"] = { type ='value', },
["GLFW_KEY_REPEAT"] = { type ='value', },
["GLFW_AUTO_POLL_EVENTS"] = { type ='value', },
["GLFW_WAIT"] = { type ='value', },
["GLFW_NOWAIT"] = { type ='value', },
["GLFW_PRESENT"] = { type ='value', },
["GLFW_AXES"] = { type ='value', },
["GLFW_BUTTONS"] = { type ='value', },
["GLFW_NO_RESCALE_BIT"] = { type ='value', },
["GLFW_ORIGIN_UL_BIT"] = { type ='value', },
["GLFW_BUILD_MIPMAPS_BIT"] = { type ='value', },
["GLFW_ALPHA_MAP_BIT"] = { type ='value', },
["glfwInit"] = { type ='function',
description = "",
returns = "(int)",
valuetype = nil,
args = "(void)", },
["glfwTerminate"] = { type ='function',
description = "",
returns = "()",
valuetype = nil,
args = "(void)", },
["glfwGetVersion"] = { type ='function',
description = "",
returns = "()",
valuetype = nil,
args = "(int *major, int *minor, int *rev)", },
["glfwOpenWindow"] = { type ='function',
description = "",
returns = "(int)",
valuetype = nil,
args = "(int width, int height, int redbits, int greenbits, int bluebits, int alphabits, int depthbits, int stencilbits, int mode)", },
["glfwOpenWindowHint"] = { type ='function',
description = "",
returns = "()",
valuetype = nil,
args = "(int target, int hint)", },
["glfwCloseWindow"] = { type ='function',
description = "",
returns = "()",
valuetype = nil,
args = "(void)", },
["glfwSetWindowTitle"] = { type ='function',
description = "",
returns = "()",
valuetype = nil,
args = "(const char *title)", },
["glfwGetWindowSize"] = { type ='function',
description = "",
returns = "()",
valuetype = nil,
args = "(int *width, int *height)", },
["glfwSetWindowSize"] = { type ='function',
description = "",
returns = "()",
valuetype = nil,
args = "(int width, int height)", },
["glfwSetWindowPos"] = { type ='function',
description = "",
returns = "()",
valuetype = nil,
args = "(int x, int y)", },
["glfwIconifyWindow"] = { type ='function',
description = "",
returns = "()",
valuetype = nil,
args = "(void)", },
["glfwRestoreWindow"] = { type ='function',
description = "",
returns = "()",
valuetype = nil,
args = "(void)", },
["glfwSwapBuffers"] = { type ='function',
description = "",
returns = "()",
valuetype = nil,
args = "(void)", },
["glfwSwapInterval"] = { type ='function',
description = "",
returns = "()",
valuetype = nil,
args = "(int interval)", },
["glfwGetWindowParam"] = { type ='function',
description = "",
returns = "(int)",
valuetype = nil,
args = "(int param)", },
["glfwSetWindowSizeCallback"] = { type ='function',
description = "",
returns = "()",
valuetype = nil,
args = "(GLFWwindowsizefun cbfun)", },
["glfwSetWindowCloseCallback"] = { type ='function',
description = "",
returns = "()",
valuetype = nil,
args = "(GLFWwindowclosefun cbfun)", },
["glfwSetWindowRefreshCallback"] = { type ='function',
description = "",
returns = "()",
valuetype = nil,
args = "(GLFWwindowrefreshfun cbfun)", },
["glfwGetVideoModes"] = { type ='function',
description = "",
returns = "(int)",
valuetype = nil,
args = "(GLFWvidmode *list, int maxcount)", },
["glfwGetDesktopMode"] = { type ='function',
description = "",
returns = "()",
valuetype = nil,
args = "(GLFWvidmode *mode)", },
["glfwPollEvents"] = { type ='function',
description = "",
returns = "()",
valuetype = nil,
args = "(void)", },
["glfwWaitEvents"] = { type ='function',
description = "",
returns = "()",
valuetype = nil,
args = "(void)", },
["glfwGetKey"] = { type ='function',
description = "",
returns = "(int)",
valuetype = nil,
args = "(int key)", },
["glfwGetMouseButton"] = { type ='function',
description = "",
returns = "(int)",
valuetype = nil,
args = "(int button)", },
["glfwGetMousePos"] = { type ='function',
description = "",
returns = "()",
valuetype = nil,
args = "(int *xpos, int *ypos)", },
["glfwSetMousePos"] = { type ='function',
description = "",
returns = "()",
valuetype = nil,
args = "(int xpos, int ypos)", },
["glfwGetMouseWheel"] = { type ='function',
description = "",
returns = "(int)",
valuetype = nil,
args = "(void)", },
["glfwSetMouseWheel"] = { type ='function',
description = "",
returns = "()",
valuetype = nil,
args = "(int pos)", },
["glfwSetKeyCallback"] = { type ='function',
description = "",
returns = "()",
valuetype = nil,
args = "(GLFWkeyfun cbfun)", },
["glfwSetCharCallback"] = { type ='function',
description = "",
returns = "()",
valuetype = nil,
args = "(GLFWcharfun cbfun)", },
["glfwSetMouseButtonCallback"] = { type ='function',
description = "",
returns = "()",
valuetype = nil,
args = "(GLFWmousebuttonfun cbfun)", },
["glfwSetMousePosCallback"] = { type ='function',
description = "",
returns = "()",
valuetype = nil,
args = "(GLFWmouseposfun cbfun)", },
["glfwSetMouseWheelCallback"] = { type ='function',
description = "",
returns = "()",
valuetype = nil,
args = "(GLFWmousewheelfun cbfun)", },
["glfwGetJoystickParam"] = { type ='function',
description = "",
returns = "(int)",
valuetype = nil,
args = "(int joy, int param)", },
["glfwGetJoystickPos"] = { type ='function',
description = "",
returns = "(int)",
valuetype = nil,
args = "(int joy, float *pos, int numaxes)", },
["glfwGetJoystickButtons"] = { type ='function',
description = "",
returns = "(int)",
valuetype = nil,
args = "(int joy, unsigned char *buttons, int numbuttons)", },
["glfwGetTime"] = { type ='function',
description = "",
returns = "(double)",
valuetype = nil,
args = "(void)", },
["glfwSetTime"] = { type ='function',
description = "",
returns = "(void)",
valuetype = nil,
args = "(double time)", },
["glfwSleep"] = { type ='function',
description = "",
returns = "(void)",
valuetype = nil,
args = "(double time)", },
["glfwExtensionSupported"] = { type ='function',
description = "",
returns = "(int)",
valuetype = nil,
args = "(const char *extension)", },
["glfwGetProcAddress"] = { type ='function',
description = "",
returns = "(void*)",
valuetype = nil,
args = "(const char *procname)", },
["glfwGetGLVersion"] = { type ='function',
description = "",
returns = "(void)",
valuetype = nil,
args = "(int *major, int *minor, int *rev)", },
["glfwCreateThread"] = { type ='function',
description = "",
returns = "(GLFWthread)",
valuetype = nil,
args = "(GLFWthreadfun fun, void *arg)", },
["glfwDestroyThread"] = { type ='function',
description = "",
returns = "()",
valuetype = nil,
args = "(GLFWthread ID)", },
["glfwWaitThread"] = { type ='function',
description = "",
returns = "(int)",
valuetype = nil,
args = "(GLFWthread ID, int waitmode)", },
["glfwGetThreadID"] = { type ='function',
description = "",
returns = "(GLFWthread)",
valuetype = nil,
args = "(void)", },
["glfwCreateMutex"] = { type ='function',
description = "",
returns = "(GLFWmutex)",
valuetype = nil,
args = "(void)", },
["glfwDestroyMutex"] = { type ='function',
description = "",
returns = "()",
valuetype = nil,
args = "(GLFWmutex mutex)", },
["glfwLockMutex"] = { type ='function',
description = "",
returns = "()",
valuetype = nil,
args = "(GLFWmutex mutex)", },
["glfwUnlockMutex"] = { type ='function',
description = "",
returns = "()",
valuetype = nil,
args = "(GLFWmutex mutex)", },
["glfwCreateCond"] = { type ='function',
description = "",
returns = "(GLFWcond)",
valuetype = nil,
args = "(void)", },
["glfwDestroyCond"] = { type ='function',
description = "",
returns = "()",
valuetype = nil,
args = "(GLFWcond cond)", },
["glfwWaitCond"] = { type ='function',
description = "",
returns = "()",
valuetype = nil,
args = "(GLFWcond cond, GLFWmutex mutex, double timeout)", },
["glfwSignalCond"] = { type ='function',
description = "",
returns = "()",
valuetype = nil,
args = "(GLFWcond cond)", },
["glfwBroadcastCond"] = { type ='function',
description = "",
returns = "()",
valuetype = nil,
args = "(GLFWcond cond)", },
["glfwGetNumberOfProcessors"] = { type ='function',
description = "",
returns = "(int)",
valuetype = nil,
args = "(void)", },
["glfwEnable"] = { type ='function',
description = "",
returns = "()",
valuetype = nil,
args = "(int token)", },
["glfwDisable"] = { type ='function',
description = "",
returns = "()",
valuetype = nil,
args = "(int token)", },
["glfwReadImage"] = { type ='function',
description = "",
returns = "(int)",
valuetype = nil,
args = "(const char *name, GLFWimage *img, int flags)", },
["glfwReadMemoryImage"] = { type ='function',
description = "",
returns = "(int)",
valuetype = nil,
args = "(const void *data, long size, GLFWimage *img, int flags)", },
["glfwFreeImage"] = { type ='function',
description = "",
returns = "()",
valuetype = nil,
args = "(GLFWimage *img)", },
["glfwLoadTexture2D"] = { type ='function',
description = "",
returns = "(int)",
valuetype = nil,
args = "(const char *name, int flags)", },
["glfwLoadMemoryTexture2D"] = { type ='function',
description = "",
returns = "(int)",
valuetype = nil,
args = "(const void *data, long size, int flags)", },
["glfwLoadTextureImage2D"] = { type ='function',
description = "",
returns = "(int)",
valuetype = nil,
args = "(GLFWimage *img, int flags)", },
["GLFWvidmode"] = { type ='class',
description = "",
childs = {
["Width"] = { type ='value', description = "int", valuetype = nil, },
["Height"] = { type ='value', description = "int", valuetype = nil, },
["RedBits"] = { type ='value', description = "int", valuetype = nil, },
["BlueBits"] = { type ='value', description = "int", valuetype = nil, },
["GreenBits"] = { type ='value', description = "int", valuetype = nil, },
}
},
["GLFWimage"] = { type ='class',
description = "",
childs = {
["Width"] = { type ='value', description = "int", valuetype = nil, },
["Height"] = { type ='value', description = "int", valuetype = nil, },
["Format"] = { type ='value', description = "int", valuetype = nil, },
["BytesPerPixel"] = { type ='value', description = "int", valuetype = nil, },
}
},
}
return {
glfw = {
type = 'lib',
description = "GLFW window manager",
childs = api,
},
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
This directory contains API definitions.
An API definition is a set of functions that are used
for displaying tooltip information on function calls or
autocomplete information.
This directory contains API definitions.
An API definition is a set of functions that are used
for displaying tooltip information on function calls or
autocomplete information.

Binary file not shown.

Binary file not shown.

BIN
bin/winapi.dll Normal file

Binary file not shown.

View File

@@ -1,38 +1,38 @@
styles = {
-- lexer specific (inherit fg/bg from text)
lexerdef = {fg = {128, 128, 128},},
comment = {fg = {0, 127, 0 },bg = {240, 240, 220}, fill= true,},
stringtxt = {fg = {127, 0, 127},},
stringeol = {fg = {0, 0, 0 },bg = {224, 192, 224}, fill = true, },
preprocessor = {fg = {127, 127, 0 },},
operator = {fg = {0, 0, 0 },},
number = {fg = {90, 100, 0 },},
keywords0 = {fg = {0, 0, 127}, b = true,},
keywords1 = {fg = {127, 0, 0}, b = true,},
keywords2 = {fg = {0, 127, 0}, b = true,},
keywords3 = {fg = {0, 0, 127}, b = true,},
keywords4 = {fg = {127, 0, 95}, b = true,},
keywords5 = {fg = {35, 95, 175}, b = true,},
keywords6 = {fg = {0, 127, 127}, b = true,},
keywords7 = {fg = {240, 255, 255}, b = true,},
-- common (inherit fg/bg from text)
text = nil, -- let os pick
linenumber = {fg = {90, 90, 80},},
bracematch = {fg = {0, 0, 255}, b = true},
bracemiss = {fg = {255, 0, 0 }, b = true},
ctrlchar = nil,
indent = {fg = {192, 192, 192},bg = {255, 255, 255},},
calltip = nil,
-- common special (need custom fg & bg)
calltipbg = nil,
sel = nil,
caret = nil,
caretlinebg = nil,
fold = nil,
whitespace = {fg = {180, 180, 180,},},
fncall = {fg = {175,175,255}, st= wxstc.wxSTC_INDIC_BOX},
}
styles = {
-- lexer specific (inherit fg/bg from text)
lexerdef = {fg = {128, 128, 128},},
comment = {fg = {0, 127, 0 },bg = {240, 240, 220}, fill= true,},
stringtxt = {fg = {127, 0, 127},},
stringeol = {fg = {0, 0, 0 },bg = {224, 192, 224}, fill = true, },
preprocessor = {fg = {127, 127, 0 },},
operator = {fg = {0, 0, 0 },},
number = {fg = {90, 100, 0 },},
keywords0 = {fg = {0, 0, 127}, b = true,},
keywords1 = {fg = {127, 0, 0}, b = true,},
keywords2 = {fg = {0, 127, 0}, b = true,},
keywords3 = {fg = {0, 0, 127}, b = true,},
keywords4 = {fg = {127, 0, 95}, b = true,},
keywords5 = {fg = {35, 95, 175}, b = true,},
keywords6 = {fg = {0, 127, 127}, b = true,},
keywords7 = {fg = {240, 255, 255}, b = true,},
-- common (inherit fg/bg from text)
text = nil, -- let os pick
linenumber = {fg = {90, 90, 80},},
bracematch = {fg = {0, 0, 255}, b = true},
bracemiss = {fg = {255, 0, 0 }, b = true},
ctrlchar = nil,
indent = {fg = {192, 192, 192},bg = {255, 255, 255},},
calltip = nil,
-- common special (need custom fg & bg)
calltipbg = nil,
sel = nil,
caret = nil,
caretlinebg = nil,
fold = nil,
whitespace = {fg = {180, 180, 180,},},
fncall = {fg = {175,175,255}, st= wxstc.wxSTC_INDIC_BOX},
}

View File

@@ -1,54 +0,0 @@
local luxpath = os.getenv("LUXINIA")
path.luxinia = luxpath and luxpath.."/" or "../../engine/"
local luxpath2 = os.getenv("LUXINIA2")
path.luxinia2 = luxpath2 and luxpath2.."/" or "../luxinia2/runtime/bin_Windows_x86/"
editor.fontname = "Courier New"
editor.caretline = true
editor.showfncall = true
filehistorylength = 20
singleinstance = true
singleinstanceport = 0xe493
acandtip.shorttip = true
styles = {
-- lexer specific (inherit fg/bg from text)
lexerdef = {fg = {128, 128, 128},},
comment = {fg = {0, 127, 0 },bg = {240, 240, 220}, fill= true,},
stringtxt = {fg = {127, 0, 127},},
stringeol = {fg = {0, 0, 0 },bg = {224, 192, 224}, fill = true, },
preprocessor = {fg = {127, 127, 0 },},
operator = {fg = {0, 0, 0 },},
number = {fg = {90, 100, 0 },},
keywords0 = {fg = {0, 0, 127}, b = true,},
keywords1 = {fg = {127, 0, 0}, b = true,},
keywords2 = {fg = {0, 127, 0}, b = true,},
keywords3 = {fg = {0, 0, 127}, b = true,},
keywords4 = {fg = {127, 0, 95}, b = true,},
keywords5 = {fg = {35, 95, 175}, b = true,},
keywords6 = {fg = {0, 127, 127}, b = true,},
keywords7 = {fg = {240, 255, 255}, b = true,},
-- common (inherit fg/bg from text)
text = nil, -- let os pick
linenumber = {fg = {90, 90, 80},},
bracematch = {fg = {0, 0, 255}, b = true},
bracemiss = {fg = {255, 0, 0 }, b = true},
ctrlchar = nil,
indent = {fg = {192, 192, 192},bg = {255, 255, 255},},
calltip = nil,
-- common special (need custom fg & bg)
calltipbg = nil,
sel = nil,
caret = nil,
caretlinebg = nil,
fold = nil,
whitespace = nil,
fncall = {fg = {175,175,255}, st= wxstc.wxSTC_INDIC_BOX},
}

View File

@@ -1,39 +1,38 @@
styles = {
-- lexer specific (inherit fg/bg from text)
lexerdef = {fg = {128, 128, 128},},
comment = {fg = {200, 230, 120 },bg = {30, 40, 30 }, fill= true,},
stringtxt = {fg = {240,128,240},},
stringeol = {fg = {240,128,200},bg = {48, 24, 24}, fill = true,},
preprocessor = {fg = {220,175,140},},
operator = {fg = {210, 230, 240 },},
number = {fg = {210, 230, 255, },},
keywords0 = {fg = {240,240,0}},
keywords1 = {fg = {255,64,64},},
keywords2 = {fg = {0,240,240},},
keywords3 = {fg = {140,140,240},},
keywords4 = {fg = {255, 128, 0},},
keywords5 = {fg = {200,200,240},},
keywords6 = {fg = {64, 250, 64},},
keywords7 = {fg = {255, 128, 128},},
-- common (inherit fg/bg from text)
text = {fg = {240,240,240},bg = {24,24,24},},
linenumber = {fg = {30, 30, 40},bg = {230, 230, 230},},
bracematch = {fg = {255, 127, 0}, b = true},
bracemiss = {fg = {255, 0,0}, b = true},
ctrlchar = nil,
indent = {fg = {80, 80, 80},bg = {24,24,24},},
calltip = {fg = {255,255,255},bg = {10,10,10},},
-- common special (need custom fg & bg)
calltipbg = {fg = {240,240,240},bg = {10,10,10},},
sel = {fg = {180,220,140},bg = {70,105,100},},
caret = {fg = {250,250,250},},
caretlinebg = {fg = {180,220,140},bg = {24,44,44},},
fold = nil,
whitespace = {fg = {54,54,54},},
fncall = {fg = {140,140,0}, st = wxstc.wxSTC_INDIC_BOX},
}
styles = {
-- lexer specific (inherit fg/bg from text)
lexerdef = {fg = {128, 128, 128},},
comment = {fg = {200, 230, 120 },bg = {30, 40, 30 }, fill= true,},
stringtxt = {fg = {240,128,240},},
stringeol = {fg = {240,128,200},bg = {48, 24, 24}, fill = true,},
preprocessor = {fg = {220,175,140},},
operator = {fg = {210, 230, 240 },},
number = {fg = {210, 230, 255, },},
keywords0 = {fg = {240,240,0}},
keywords1 = {fg = {255,64,64},},
keywords2 = {fg = {0,240,240},},
keywords3 = {fg = {140,140,240},},
keywords4 = {fg = {255, 128, 0},},
keywords5 = {fg = {200,200,240},},
keywords6 = {fg = {64, 250, 64},},
keywords7 = {fg = {255, 128, 128},},
-- common (inherit fg/bg from text)
text = {fg = {240,240,240},bg = {24,24,24},},
linenumber = {fg = {30, 30, 40},bg = {230, 230, 230},},
bracematch = {fg = {255, 127, 0}, b = true},
bracemiss = {fg = {255, 0,0}, b = true},
ctrlchar = nil,
indent = {fg = {80, 80, 80},bg = {24,24,24},},
calltip = {fg = {255,255,255},bg = {10,10,10},},
-- common special (need custom fg & bg)
calltipbg = {fg = {240,240,240},bg = {10,10,10},},
sel = {fg = {180,220,140},bg = {70,105,100},},
caret = {fg = {250,250,250},},
caretlinebg = {fg = {180,220,140},bg = {24,44,44},},
fold = nil,
whitespace = {fg = {54,54,54},},
fncall = {fg = {140,140,0}, st = wxstc.wxSTC_INDIC_BOX},
}

View File

@@ -1,39 +1,38 @@
styles = {
-- lexer specific (inherit fg/bg from text)
lexerdef = {fg = {128, 128, 128},},
comment = {fg = {100, 155, 65}, bg = {30, 35, 30 }, fill= true,},
stringtxt = {fg = {200, 145, 145},},
stringeol = {fg = {200, 145, 145},bg = {48, 24, 24}, fill = true,},
preprocessor = {fg = {220, 175, 140},},
operator = {fg = {210, 230, 240 },},
number = {fg = {210, 230, 255, },},
keywords0 = {fg = {128,128,255},},
keywords1 = {fg = {210,90,90},},
keywords2 = {fg = {0,220,220},},
keywords3 = {fg = {220,220,0},},
keywords4 = {fg = {240, 128,0},},
keywords5 = {fg = {200,200,240},},
keywords6 = {fg = {64, 240, 64},},
keywords7 = {fg = {255, 128, 128},},
-- common (inherit fg/bg from text)
text = {fg = {200,200,200},bg = {18,24,26},},
linenumber = {fg = {30, 30, 40},bg = {230, 230, 230},},
bracematch = {fg = {255, 127, 0}, b = true},
bracemiss = {fg = {255, 0,0}, b = true},
ctrlchar = nil,
indent = {fg = {80, 80, 80},bg = {24,24,24},},
calltip = {fg = {255,255,255},bg = {10,10,10},},
-- common special (need custom fg & bg)
calltipbg = {fg = {240,240,240},bg = {10,10,10},},
sel = {fg = {180,220,140},bg = {70,105,100},},
caret = {fg = {250,250,250},},
caretlinebg = {fg = {180,220,140},bg = {24,44,44},},
fold = nil,
whitespace = {fg = {54,54,54},},
fncall = {fg = {75,75,150}, st= wxstc.wxSTC_INDIC_BOX},
}
styles = {
-- lexer specific (inherit fg/bg from text)
lexerdef = {fg = {128, 128, 128},},
comment = {fg = {100, 155, 65}, bg = {30, 35, 30 }, fill= true,},
stringtxt = {fg = {200, 145, 145},},
stringeol = {fg = {200, 145, 145},bg = {48, 24, 24}, fill = true,},
preprocessor = {fg = {220, 175, 140},},
operator = {fg = {210, 230, 240 },},
number = {fg = {210, 230, 255, },},
keywords0 = {fg = {128,128,255},},
keywords1 = {fg = {210,90,90},},
keywords2 = {fg = {0,220,220},},
keywords3 = {fg = {220,220,0},},
keywords4 = {fg = {240, 128,0},},
keywords5 = {fg = {200,200,240},},
keywords6 = {fg = {64, 240, 64},},
keywords7 = {fg = {255, 128, 128},},
-- common (inherit fg/bg from text)
text = {fg = {200,200,200},bg = {18,24,26},},
linenumber = {fg = {30, 30, 40},bg = {230, 230, 230},},
bracematch = {fg = {255, 127, 0}, b = true},
bracemiss = {fg = {255, 0,0}, b = true},
ctrlchar = nil,
indent = {fg = {80, 80, 80},bg = {24,24,24},},
calltip = {fg = {255,255,255},bg = {10,10,10},},
-- common special (need custom fg & bg)
calltipbg = {fg = {240,240,240},bg = {10,10,10},},
sel = {fg = {180,220,140},bg = {70,105,100},},
caret = {fg = {250,250,250},},
caretlinebg = {fg = {180,220,140},bg = {24,44,44},},
fold = nil,
whitespace = {fg = {54,54,54},},
fncall = {fg = {75,75,150}, st= wxstc.wxSTC_INDIC_BOX},
}

View File

@@ -0,0 +1,9 @@
--[[--
estrela loads configs in the following order
1. <application>\config.lua
2. cfg\user.lua
3. -cfg commandline strings
--]]--

View File

@@ -1,52 +0,0 @@
local luxpath = os.getenv("LUXINIA")
path.luxinia = luxpath and luxpath.."/" or "../luxinia/"
interpreter = "estrelashell"
acandtip.shorttip = true
acandtip.nodynwords = true
editor.iofilter = "GermanUtf8Ascii"
cgprofile = "gp4"
cgperfgpu = "G80"
--[[
styles = {
-- lexer specific (inherit fg/bg from text)
lexerdef = {fg = {128, 128, 128},},
comment = {fg = {200, 230, 120 },bg = {30, 40, 30 }, fill= true,},
stringtxt = {fg = {240,128,240},},
stringeol = {fg = {240,128,200},bg = {48, 24, 24}, fill = true,},
preprocessor = {fg = {220,175,140},},
operator = {fg = {210, 230, 240 },},
number = {fg = {210, 230, 255, },},
keywords0 = {fg = {240,240,0}},
keywords1 = {fg = {255,64,64},},
keywords2 = {fg = {0,240,240},},
keywords3 = {fg = {140,140,240},},
keywords4 = {fg = {255, 128, 0},},
keywords5 = {fg = {200,200,240},},
keywords6 = {fg = {64, 250, 64},},
keywords7 = {fg = {255, 128, 128},},
-- common (inherit fg/bg from text)
text = {fg = {240,240,240},bg = {24,24,24},},
linenumber = {fg = {30, 30, 40},bg = {230, 230, 230},},
bracematch = {fg = {200, 200, 0}, b = true},
bracemiss = {fg = {255, 50, 50 }, b = true},
ctrlchar = nil,
indent = {fg = {80, 80, 80},bg = {24,24,24},},
calltip = {fg = {255,255,255},bg = {10,10,10},},
-- common special (need custom fg & bg)
calltipbg = {fg = {240,240,240},bg = {10,10,10},},
sel = {fg = {180,220,140},bg = {70,105,100},},
caret = {fg = {250,250,250},},
caretlinebg = {fg = {180,220,140},bg = {24,44,44},},
fold = nil,
whitespace = {fg = {224,224,224},bg = {24,24,24},},
}
]]

View File

@@ -1,51 +0,0 @@
local luxpath = os.getenv("LUXINIA")
path.luxinia = luxpath and luxpath.."/" or "../luxinia/"
path.cgbin = "../Cg/bin"
interpreter = "luxinia"
acandtip.shorttip = true
acandtip.nodynwords = true
editor.iofilter = "GermanUtf8Ascii"
--[[
styles = {
-- lexer specific (inherit fg/bg from text)
lexerdef = {fg = {128, 128, 128},},
comment = {fg = {200, 230, 120 },bg = {30, 40, 30 }, fill= true,},
stringtxt = {fg = {240,128,240},},
stringeol = {fg = {240,128,200},bg = {48, 24, 24}, fill = true,},
preprocessor = {fg = {220,175,140},},
operator = {fg = {210, 230, 240 },},
number = {fg = {210, 230, 255, },},
keywords0 = {fg = {240,240,0}},
keywords1 = {fg = {255,64,64},},
keywords2 = {fg = {0,240,240},},
keywords3 = {fg = {140,140,240},},
keywords4 = {fg = {255, 128, 0},},
keywords5 = {fg = {200,200,240},},
keywords6 = {fg = {64, 250, 64},},
keywords7 = {fg = {255, 128, 128},},
-- common (inherit fg/bg from text)
text = {fg = {240,240,240},bg = {24,24,24},},
linenumber = {fg = {30, 30, 40},bg = {230, 230, 230},},
bracematch = {fg = {200, 200, 0}, b = true},
bracemiss = {fg = {255, 50, 50 }, b = true},
ctrlchar = nil,
indent = {fg = {80, 80, 80},bg = {24,24,24},},
calltip = {fg = {255,255,255},bg = {10,10,10},},
-- common special (need custom fg & bg)
calltipbg = {fg = {240,240,240},bg = {10,10,10},},
sel = {fg = {180,220,140},bg = {70,105,100},},
caret = {fg = {250,250,250},},
caretlinebg = {fg = {180,220,140},bg = {24,44,44},},
fold = nil,
whitespace = {fg = {224,224,224},bg = {24,24,24},},
}
]]

View File

@@ -1,289 +0,0 @@
-- About
-- ----------------------------------------------------
-- This file contains lua table definitons used by
-- automatic loaded files, not part of the
-- editor source.
--
-- /cfg/config.lua
-- /cfg/user.lua
-- /spec/*.lua
-- /tools/*.lua
-- /api/*<apitype>/*.lua
-- style definition
-- ----------------------------------------------------
-- all entries are optiona
stattr = {
fg = {r,g,b}, -- foreground color 0-255
bg = {r,g,b}, -- background color
i = false, -- italic
b = false, -- bold
u = false, -- underline
fill = true, -- fill to lineend
}
style = {
-- lexer specific (inherit fg/bg from text)
lexerdef = stattr,
comment = stattr,
stringtxt = stattr,
stringeol = stattr,
preprocessor = stattr,
operator = stattr,
number = stattr,
keywords0 = stattr,
keywords1 = stattr,
keywords2 = stattr,
keywords3 = stattr,
keywords4 = stattr,
keywords5 = stattr,
keywords6 = stattr,
keywords7 = stattr,
-- common (inherit fg/bg from text)
text = stattr,
linenumber = stattr,
bracematch = stattr,
bracemiss = stattr,
escapechar = stattr,
indent = stattr,
calltip = stattr,
-- common special (need custom fg & bg )
calltipbg = nil,
sel = nil,
caret = nil,
caretlinebg = nil,
fold = nil,
whitespace = nil,
-- special, functioncall indicator
fncall = {
fg = {r,g,b},
st = wxstc.wxSTC_INDIC_BOX,
},
}
-- config definition
-- ----------------------------------------------------
-- tables must exist
-- content is optional
-- config is loaded into existing config table
config = {
appname = "estrela", -- by default the launcher name
path = {
-- path for tools/interpreters
luxinia = "C:/luxbin/",
-- path to luxinia exe
projectdir = "",
-- the project directory, used by
-- some tools/interpreters
},
editor = {
fontname = "Courier New",
-- default font
fontsize = 10,
-- defailt size
caretline = true,
-- show active line
-- input/output filtering of strings
-- current filters "GermanUtf8Ascii"
iofilter = nil,
-- use indicator to show function calls
-- if spec allows
showfncall = true,
tabwidth = 4,
usetabs = true, -- if false then spaces are used
whitespace = false,
autotabs = true, -- if true test for tabs after file load,
-- sets "usetabs" to true for this file
},
outputshell = {
-- output and shell settings
fontname = "Courier New",
-- default font
fontsize = 10,
-- defult size
}
styles = {},
-- styles table as above for editor
stylesoutshell = {},
-- styles for output/shell
interpreter = "EstrelaEditor",
-- the default "project" lua interpreter
-- EstrelaEditor, Luxinia, Lua
autocomplete = true,
-- whether autocomplete is on by default
acandtip = {
shorttip = false,
-- tooltips are compact during typing
nodynwords = false,
-- no dynamic words (user entered words)
ignorecase = false,
-- ignores case when performing comparison with autocomplete list
strategy = 0,
-- 0: is string comparison
-- 1: substring leading characters (camel case or _ separated)
-- 2: leading + any correctly ordered fragments (default)
}
savebak = false,
-- if bak files are created on save
filehistorylength = 20,
-- historylength for files
projecthistorylength = 15,
-- historylength for project directories
singleinstance = true,
-- if true creates a UDP server to exchange messages
-- for loading commandline passed files
singleinstanceport = 0xe493,
-- UDP port for single instance communication
}
-- application engine
-- ----------------------------------------------------
app = {
postinit = function() end, -- post init, prior starting mainloop
loadfilters = {
tools = function(file) return true end,
specs = function(file) return true end,
interpreters = function(file) return true end,
}
stringtable = { -- optional entries uses defaults otherwise
editor = nil,
statuswelcome = nil,
}
}
-- api definition
-- ----------------------------------------------------
-- hierarchy encoded into children
api = {
-- global space words, e.g "table"
["blah"] = {
-- "function", "class", "keyword", "value", "lib"
type = "function",
description = "this does something",
-- value and function:
valuetype = "api.ClassName",
-- function:
args = "(blah,blubb)",
returns = "(foo)",
-- autogenerated post load:
-- concated hierarchy name (e.g. "lib.class")
classname = "blah",
-- children in the class hierarchy
childs = {
--.. recursive
}
},
["blubb"] = {
--...
},
}
-- spec definition
-- ----------------------------------------------------
-- all entries are optional
spec = {
exts = {"ext","ext2",..},
-- compatible extensions
lexer = wxstc.wxSTC_LEX_LUA,
-- scintilla lexer
lexerstyleconvert = {
-- table mapping each styles to
-- appropriate lexer id
stringeol = {wxstc.wxSTC_LUA_STRINGEOL,},
-- ...
}
linecomment = "//",
-- string for linecomments
sep = "[%.:]",
-- class.function separator match string,
-- e.g in lua both . and : are allowed
-- default is "\1" which should yield no matches
-- and therefore disable class.func type autocompletion
isfncall = function(str) return from,to end
-- function that detects positions for a substring that
-- stands for a functioncall, ie " call(..)" -> 2,5
apitype = "api",
-- which sub directory of "api" is relevant
-- api files handle autocomplete and tooltips
-- api won't affect syntax coloring
keywords = {
-- up to 8 strings containing space separated keywords
-- used by the lexer for coloring (NOT for autocomplete).
-- however each lexer supports varying amount
-- of keyword types
"foo bar word",
"more words",
}
}
-- tool definition
-- ----------------------------------------------------
-- main entries are optional
tool = {
fninit = function(frame,menubar) end,
-- guarantees that ide is initialized
-- can be used for init
-- and adding custom menu
exec = {
-- quick exec action, listed under "Tools" menu
name = "",
description = "",
fn = function(wxfilename,projectdir) end,
}
}
-- interpreter definition
-- ----------------------------------------------------
interpreter = {
name = "",
description = "",
api = {"apifile_without_extension"} -- optional to limit loaded apis
frun = function(self,wfilename)
return "execommand"
end,
fprojdir = function(self,wfilename)
return "projpath_from_filename" -- optional
end,
}

View File

@@ -1,54 +1,54 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<CodeBlocks_project_file>
<FileVersion major="1" minor="6" />
<Project>
<Option title="starter" />
<Option pch_mode="2" />
<Option compiler="gcc" />
<Build>
<Target title="Debug">
<Option output="..\..\estrela" prefix_auto="1" extension_auto="1" />
<Option working_dir="..\..\" />
<Option object_output="obj\Debug\" />
<Option type="1" />
<Option compiler="gcc" />
<Option use_console_runner="0" />
<Compiler>
<Add option="-g" />
</Compiler>
</Target>
<Target title="Release">
<Option output="..\..\estrela" prefix_auto="1" extension_auto="1" />
<Option working_dir="..\..\" />
<Option object_output="obj\Release\" />
<Option type="0" />
<Option compiler="gcc" />
<Compiler>
<Add option="-O2" />
</Compiler>
<Linker>
<Add option="-s" />
</Linker>
</Target>
</Build>
<Compiler>
<Add option="-Wall" />
<Add option="-D__MINGW__" />
</Compiler>
<Linker>
<Add library="kernel32" />
</Linker>
<Unit filename="..\res\estrela.ico" />
<Unit filename="..\res\estrela.rc">
<Option compilerVar="WINDRES" />
</Unit>
<Unit filename="..\win32_starter.c">
<Option compilerVar="CC" />
</Unit>
<Extensions>
<code_completion />
<envvars />
<debugger />
</Extensions>
</Project>
</CodeBlocks_project_file>
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<CodeBlocks_project_file>
<FileVersion major="1" minor="6" />
<Project>
<Option title="starter" />
<Option pch_mode="2" />
<Option compiler="gcc" />
<Build>
<Target title="Debug">
<Option output="..\..\estrela" prefix_auto="1" extension_auto="1" />
<Option working_dir="..\..\" />
<Option object_output="obj\Debug\" />
<Option type="1" />
<Option compiler="gcc" />
<Option use_console_runner="0" />
<Compiler>
<Add option="-g" />
</Compiler>
</Target>
<Target title="Release">
<Option output="..\..\estrela" prefix_auto="1" extension_auto="1" />
<Option working_dir="..\..\" />
<Option object_output="obj\Release\" />
<Option type="0" />
<Option compiler="gcc" />
<Compiler>
<Add option="-O2" />
</Compiler>
<Linker>
<Add option="-s" />
</Linker>
</Target>
</Build>
<Compiler>
<Add option="-Wall" />
<Add option="-D__MINGW__" />
</Compiler>
<Linker>
<Add library="kernel32" />
</Linker>
<Unit filename="..\res\estrela.ico" />
<Unit filename="..\res\estrela.rc">
<Option compilerVar="WINDRES" />
</Unit>
<Unit filename="..\win32_starter.c">
<Option compilerVar="CC" />
</Unit>
<Extensions>
<code_completion />
<envvars />
<debugger />
</Extensions>
</Project>
</CodeBlocks_project_file>

61
estrela/config.lua Normal file
View File

@@ -0,0 +1,61 @@
local luxpath = os.getenv("LUXINIA")
path.luxinia = luxpath and luxpath.."/" or "../luxinia/engine/"
local luxpath2 = os.getenv("LUXINIA2")
path.luxinia2 = luxpath2 and luxpath2.."/" or "../luxinia2/runtime/bin_Windows_x86/"
interpreter = "estrelashell"
editor.fontname = "Courier New"
editor.caretline = true
editor.showfncall = true
editor.whitespace = true
editor.usetabs = false
editor.autotabs = true
editor.tabwidth = 2
filehistorylength = 20
singleinstance = true
singleinstanceport = 0xe493
acandtip.shorttip = true
acandtip.nodynwords = true
acandtip.ignorecase = true
styles = {
-- lexer specific (inherit fg/bg from text)
lexerdef = {fg = {128, 128, 128},},
comment = {fg = {0, 127, 0 },bg = {240, 240, 220}, fill= true,},
stringtxt = {fg = {127, 0, 127},},
stringeol = {fg = {0, 0, 0 },bg = {224, 192, 224}, fill = true, },
preprocessor = {fg = {127, 127, 0 },},
operator = {fg = {0, 0, 0 },},
number = {fg = {90, 100, 0 },},
keywords0 = {fg = {0, 0, 127}, b = true,},
keywords1 = {fg = {127, 0, 0}, b = true,},
keywords2 = {fg = {0, 127, 0}, b = true,},
keywords3 = {fg = {0, 0, 127}, b = true,},
keywords4 = {fg = {127, 0, 95}, b = true,},
keywords5 = {fg = {35, 95, 175}, b = true,},
keywords6 = {fg = {0, 127, 127}, b = true,},
keywords7 = {fg = {240, 255, 255}, b = true,},
-- common (inherit fg/bg from text)
text = nil, -- let os pick
linenumber = {fg = {90, 90, 80},},
bracematch = {fg = {0, 0, 255}, b = true},
bracemiss = {fg = {255, 0, 0 }, b = true},
ctrlchar = nil,
indent = {fg = {192, 192, 192},bg = {255, 255, 255},},
calltip = nil,
-- common special (need custom fg & bg)
calltipbg = nil,
sel = nil,
caret = nil,
caretlinebg = nil,
fold = nil,
whitespace = nil,
fncall = {fg = {175,175,255}, st= wxstc.wxSTC_INDIC_BOX},
}

View File

@@ -1,114 +1,113 @@
-- authors: Lomtik Software (J. Winwood & John Labenski)
-- Luxinia Dev (Eike Decker & Christoph Kubisch)
---------------------------------------------------------
local ide = ide
-- ---------------------------------------------------------------------------
-- Create the Help menu and attach the callback functions
local frame = ide.frame
local menuBar = frame.menuBar
local helpMenu = wx.wxMenu{
{ ID_ABOUT, "&About\tF1", "About Estrela Editor" },
}
menuBar:Append(helpMenu, "&Help")
local function DisplayAbout(event)
local page = [[
<html>
<body bgcolor = "#ffffff" text='#ffffff'>
<table border='0' width="100%">
<tr><td><img src = "estrela/res/estrela.png"></center></td><td>
<table cellspacing = 4 cellpadding = 4 width = "400">
<tr>
<td bgcolor = "#010156">
<center>
<font size = +2 color = "#FFFFFF"><br><b>]]..
wxlua.wxLUA_VERSION_STRING..[[</b></font>
<font size = +1 color = "#FFFFFF">built with</font>
<font size = +2 color = "#FFFFFF"><b>]]..
wx.wxVERSION_STRING..[[</b></font>
</center>
</td>
</tr>
<tr>
<td bgcolor = "#4747A1">
<b>Estrela Editor</b><br>
<b><font color='#ffffff'>Copyright &copy; 2008-2011 Luxinia DevTeam</font></b>
<p>
<font size=-1>
<table cellpadding = 0 cellspacing = 0 width = "100%">
<tr>
<td width = "65%">
Christoph Kubisch<br>
Eike Decker<p>
</td>
<td valign = top>
</td>
</tr>
</table>
<font size = 1>
Licenced under The MIT License.
</font>
</font>
</td>
</tr>
<tr>
<td bgcolor = "#4747A1">
<b>based on wxLua editor sample</b><br>
<b>Copyright &copy; 2002-2005 Lomtick Software</b>
<p>
<font size=-1>
<table cellpadding = 0 cellspacing = 0 width = "100%">
<tr>
<td width = "65%">
J. Winwood (luascript@thersgb.net)<br>
John Labenski<p>
</td>
<td valign = top>
<img src = "estrela/res/wxlualogo2.png">
</td>
</tr>
</table>
<font size = 1>
wxLua binding licenced under wxWindows Library Licence, Version 3.
</font>
</font>
</td>
</tr>
</table>
</td></tr></table>
</body>
</html>
]]
local dlg = wx.wxDialog(frame, wx.wxID_ANY, "About Estrela Editor")
local html = wx.wxLuaHtmlWindow(dlg, wx.wxID_ANY,
wx.wxDefaultPosition, wx.wxSize(500, 270),
wx.wxHW_SCROLLBAR_NEVER)
local line = wx.wxStaticLine(dlg, wx.wxID_ANY)
local button = wx.wxButton(dlg, wx.wxID_OK, "OK")
button:SetDefault()
html:SetBorders(0)
html:SetPage(page)
html:SetSize(html:GetInternalRepresentation():GetWidth(),
html:GetInternalRepresentation():GetHeight())
local topsizer = wx.wxBoxSizer(wx.wxVERTICAL)
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)
dlg:SetAutoLayout(true)
dlg:SetSizer(topsizer)
topsizer:Fit(dlg)
dlg:ShowModal()
dlg:Destroy()
end
frame:Connect(ID_ABOUT, wx.wxEVT_COMMAND_MENU_SELECTED, DisplayAbout)
-- authors: Lomtik Software (J. Winwood & John Labenski)
-- Luxinia Dev (Eike Decker & Christoph Kubisch)
---------------------------------------------------------
local ide = ide
-- ---------------------------------------------------------------------------
-- Create the Help menu and attach the callback functions
local frame = ide.frame
local menuBar = frame.menuBar
local helpMenu = wx.wxMenu{
{ ID_ABOUT, "&About\tF1", "About Estrela Editor" },
}
menuBar:Append(helpMenu, "&Help")
local function DisplayAbout(event)
local page = [[
<html>
<body bgcolor = "#ffffff" text='#ffffff'>
<table border='0' width="100%">
<tr><td><img src = "estrela/res/estrela.png"></center></td><td>
<table cellspacing = 4 cellpadding = 4 width = "400">
<tr>
<td bgcolor = "#010156">
<center>
<font size = +2 color = "#FFFFFF"><br><b>]]..
wxlua.wxLUA_VERSION_STRING..[[</b></font>
<font size = +1 color = "#FFFFFF">built with</font>
<font size = +2 color = "#FFFFFF"><b>]]..
wx.wxVERSION_STRING..[[</b></font>
</center>
</td>
</tr>
<tr>
<td bgcolor = "#4747A1">
<b>Estrela Editor</b><br>
<b><font color='#ffffff'>Copyright &copy; 2008-2011 Luxinia DevTeam</font></b>
<p>
<font size=-1>
<table cellpadding = 0 cellspacing = 0 width = "100%">
<tr>
<td width = "65%">
Christoph Kubisch<br>
Eike Decker<p>
</td>
<td valign = top>
</td>
</tr>
</table>
<font size = 1>
Licensed under The MIT License.
</font>
</font>
</td>
</tr>
<tr>
<td bgcolor = "#4747A1">
<b>based on wxLua editor sample</b><br>
<b>Copyright &copy; 2002-2005 Lomtick Software</b>
<p>
<font size=-1>
<table cellpadding = 0 cellspacing = 0 width = "100%">
<tr>
<td width = "65%">
J. Winwood (luascript@thersgb.net)<br>
John Labenski<p>
</td>
<td valign = top>
<img src = "estrela/res/wxlualogo2.png">
</td>
</tr>
</table>
<font size = 1>
wxLua binding licensed under wxWindows Library License, Version 3.
</font>
</font>
</td>
</tr>
</table>
</td></tr></table>
</body>
</html>
]]
local dlg = wx.wxDialog(frame, wx.wxID_ANY, "About Estrela Editor")
local html = wx.wxLuaHtmlWindow(dlg, wx.wxID_ANY,
wx.wxDefaultPosition, wx.wxSize(500, 270),
wx.wxHW_SCROLLBAR_NEVER)
local line = wx.wxStaticLine(dlg, wx.wxID_ANY)
local button = wx.wxButton(dlg, wx.wxID_OK, "OK")
button:SetDefault()
html:SetBorders(0)
html:SetPage(page)
html:SetSize(html:GetInternalRepresentation():GetWidth(),
html:GetInternalRepresentation():GetHeight())
local topsizer = wx.wxBoxSizer(wx.wxVERTICAL)
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)
dlg:SetAutoLayout(true)
dlg:SetSizer(topsizer)
topsizer:Fit(dlg)
dlg:ShowModal()
dlg:Destroy()
end
frame:Connect(ID_ABOUT, wx.wxEVT_COMMAND_MENU_SELECTED, DisplayAbout)

View File

@@ -1,20 +1,20 @@
Estrela Editor
-----------------
Estrela Editor is a wxLua based IDE. It supports multiple
fileformats, "api" for autocompletion and tooltips, and custom
commandline tools. Focus is extensibility for target applications
using Lua. Its main purpose is as IDE for the 3D engine "Luxinia".
Commandline:
------------
Open File(s):
<exe> <filename> [<filename>...]
any non-option will be treated as filename
Overriding Config:
<exe> [...] -cfg "<luacode overriding config>" [...]
e.g.: estrela.exe -cfg "singleinstance=false;" somefile.lua
Estrela Editor
-----------------
Estrela Editor is a wxLua based IDE. It supports multiple
fileformats, "api" for autocompletion and tooltips, and custom
commandline tools. Focus is extensibility for target applications
using Lua. Its main purpose is as IDE for the 3D engine "Luxinia".
Commandline:
------------
Open File(s):
<exe> <filename> [<filename>...]
any non-option will be treated as filename
Overriding Config:
<exe> [...] -cfg "<luacode overriding config>" [...]
e.g.: estrela.exe -cfg "singleinstance=false;" somefile.lua

View File

@@ -1 +1 @@
icon ICON "../res/estrela.ico"
icon ICON "../res/estrela.ico"

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

View File

@@ -1,132 +1,132 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="204.22055"
height="96.006279"
id="svg3513"
sodipodi:version="0.32"
inkscape:version="0.46+devel"
version="1.0"
inkscape:export-filename="D:\dev\c\tools\wxide\res\wxlualogo2.png"
inkscape:export-xdpi="59.996075"
inkscape:export-ydpi="59.996075"
sodipodi:docname="wxlogo.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape">
<defs
id="defs3515">
<linearGradient
id="linearGradient3538">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop3540" />
<stop
style="stop-color:#e3e3eb;stop-opacity:1;"
offset="1"
id="stop3542" />
</linearGradient>
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 526.18109 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="744.09448 : 526.18109 : 1"
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
id="perspective3521" />
<inkscape:perspective
id="perspective3530"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3538"
id="linearGradient3544"
x1="88.214287"
y1="0.2142856"
x2="88.214287"
y2="81.130592"
gradientUnits="userSpaceOnUse" />
<filter
inkscape:collect="always"
id="filter4057"
x="-0.044305418"
width="1.0886108"
y="-0.10071105"
height="1.2014221">
<feGaussianBlur
inkscape:collect="always"
stdDeviation="2.2929748"
id="feGaussianBlur4059" />
</filter>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1"
inkscape:cx="98.55416"
inkscape:cy="58.784487"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="1024"
inkscape:window-height="719"
inkscape:window-x="-4"
inkscape:window-y="-4" />
<metadata
id="metadata3518">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Ebene 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-102.354,-435.00191)">
<rect
ry="12.142858"
y="-1.9285716"
x="-5"
height="85"
width="193.21428"
id="rect3546"
style="opacity:0.5;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;filter:url(#filter4057)"
transform="translate(112.85714,442.43362)" />
<rect
style="opacity:1;fill:url(#linearGradient3544);fill-opacity:1;fill-rule:nonzero;stroke:none"
id="rect3536"
width="193.21428"
height="85"
x="-5"
y="-1.9285716"
transform="translate(112.85714,442.43362)"
ry="12.142858" />
<image
y="442.43362"
x="112.85714"
id="image3532"
height="77"
width="180"
sodipodi:absref="D:\dev\c\tools\wxide\res\wxlualogo.png"
xlink:href="wxlualogo.png" />
</g>
</svg>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="204.22055"
height="96.006279"
id="svg3513"
sodipodi:version="0.32"
inkscape:version="0.46+devel"
version="1.0"
inkscape:export-filename="D:\dev\c\tools\wxide\res\wxlualogo2.png"
inkscape:export-xdpi="59.996075"
inkscape:export-ydpi="59.996075"
sodipodi:docname="wxlogo.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape">
<defs
id="defs3515">
<linearGradient
id="linearGradient3538">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop3540" />
<stop
style="stop-color:#e3e3eb;stop-opacity:1;"
offset="1"
id="stop3542" />
</linearGradient>
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 526.18109 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="744.09448 : 526.18109 : 1"
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
id="perspective3521" />
<inkscape:perspective
id="perspective3530"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3538"
id="linearGradient3544"
x1="88.214287"
y1="0.2142856"
x2="88.214287"
y2="81.130592"
gradientUnits="userSpaceOnUse" />
<filter
inkscape:collect="always"
id="filter4057"
x="-0.044305418"
width="1.0886108"
y="-0.10071105"
height="1.2014221">
<feGaussianBlur
inkscape:collect="always"
stdDeviation="2.2929748"
id="feGaussianBlur4059" />
</filter>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1"
inkscape:cx="98.55416"
inkscape:cy="58.784487"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="1024"
inkscape:window-height="719"
inkscape:window-x="-4"
inkscape:window-y="-4" />
<metadata
id="metadata3518">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Ebene 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-102.354,-435.00191)">
<rect
ry="12.142858"
y="-1.9285716"
x="-5"
height="85"
width="193.21428"
id="rect3546"
style="opacity:0.5;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;filter:url(#filter4057)"
transform="translate(112.85714,442.43362)" />
<rect
style="opacity:1;fill:url(#linearGradient3544);fill-opacity:1;fill-rule:nonzero;stroke:none"
id="rect3536"
width="193.21428"
height="85"
x="-5"
y="-1.9285716"
transform="translate(112.85714,442.43362)"
ry="12.142858" />
<image
y="442.43362"
x="112.85714"
id="image3532"
height="77"
width="180"
sodipodi:absref="D:\dev\c\tools\wxide\res\wxlualogo.png"
xlink:href="wxlualogo.png" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@@ -1,236 +1,236 @@
// this is an extremly ugly quick and dirty hack...
// maybe it could be refactored to do some error catching and
// other things, but right now it does what it should...
// (providing a single exe file in our main directory without
// polluting it with all these dlls located in the /bin folder)
#ifdef __MINGW__ /* not sure if this is the *official* define */
#define _WIN32_WINNT 0x0502
#endif
#include <windows.h>
#include <winbase.h>
#include <stdlib.h>
#include <stdio.h>
/* some typedef functions - these are not matching exactly the
original definitions, but their signature is supposed to be
compatible
Currently 10 different functions are needed - each with different signatures... */
typedef void *voidfunc ();
typedef int *varfunc (void *L,...); // quick and dirty using the varargs
typedef void varfuncvoid (void *L,...);
// from lua.h
#define LUA_GLOBALSINDEX (-10002)
static voidfunc *luaL_newstate;
static varfunc *luaL_loadbuffer;
static varfunc *luaL_openlibs;
static varfunc *lua_pcall;
static varfunc *lua_pushcclosure;
static varfunc *lua_setfield;
static varfunc *lua_tolstring;
static varfuncvoid *lua_createtable;
static varfuncvoid *lua_pushstring;
static varfuncvoid *lua_rawseti;
static int luafunc_mbox (void *L)
{
const char *title = (const char*)lua_tolstring(L,1,NULL);
const char *msg = (const char*)lua_tolstring(L,2,NULL);
MessageBox(NULL,msg,title,MB_OK|MB_ICONERROR);
return 0;
}
static const char *luacode =
"local msg = _ERRMSG; _ERRMSG = nil "
"local arg = _ARG or {}; _ARG = nil "
"xpcall("
"function() "
"(loadfile 'src/main.lua')(unpack(arg)) end,"
"function(err) msg('Uncaught lua script exception',debug.traceback(err)) end)"
;
#if defined(_WIN32) && defined (_MSC_VER)
PCHAR* CommandLineToArgvA(PCHAR CmdLine,int* _argc)
{
PCHAR* argv;
PCHAR _argv;
size_t len;
ULONG argc;
CHAR a;
size_t i, j;
BOOLEAN in_QM;
BOOLEAN in_TEXT;
BOOLEAN in_SPACE;
len = strlen(CmdLine);
i = ((len+2)/2)*sizeof(PVOID) + sizeof(PVOID);
argv = (PCHAR*)GlobalAlloc(GMEM_FIXED,
i + (len+2)*sizeof(CHAR));
_argv = (PCHAR)(((PUCHAR)argv)+i);
argc = 0;
argv[argc] = _argv;
in_QM = 0;
in_TEXT = 0;
in_SPACE = 1;
i = 0;
j = 0;
while( a = CmdLine[i] ) {
if(in_QM) {
if(a == '\"') {
in_QM = 0;
} else {
_argv[j] = a;
j++;
}
} else {
switch(a) {
case '\"':
in_QM = 1;
in_TEXT = 1;
if(in_SPACE) {
argv[argc] = _argv+j;
argc++;
}
in_SPACE = 0;
break;
case ' ':
case '\t':
case '\n':
case '\r':
if(in_TEXT) {
_argv[j] = '\0';
j++;
}
in_TEXT = 0;
in_SPACE = 1;
break;
default:
in_TEXT = 1;
if(in_SPACE) {
argv[argc] = _argv+j;
argc++;
}
_argv[j] = a;
j++;
in_SPACE = 0;
break;
}
}
i++;
}
_argv[j] = '\0';
argv[argc] = NULL;
(*_argc) = argc;
return argv;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
int argc;
char ** argv = CommandLineToArgvA(GetCommandLineA(),&argc);
#else
int main (int argc, char *argv[])
{
#endif
HINSTANCE hinstLib;
char buffer[MAX_PATH],*file;
if (!GetFullPathName(argv[0],MAX_PATH,buffer,&file)) {
MessageBox(NULL,
TEXT("Couldn't find the correct working directory"),
TEXT("Failed to start estrela"),
MB_OK|MB_ICONERROR);
return 0;
}
if (file!=NULL)
*file = 0; // finish the string, I don't need the appname
//int i;
//for (i=0;i<argc; i++)
// printf("%d %s\n",i,argv[i]);
SetCurrentDirectory(buffer);
SetDllDirectory(".\\bin\\");
hinstLib = LoadLibrary("lua5.1.dll");
if (hinstLib != NULL)
{
luaL_newstate = (voidfunc*) GetProcAddress(hinstLib, "luaL_newstate");
luaL_loadbuffer = (varfunc*) GetProcAddress(hinstLib, "luaL_loadbuffer");
luaL_openlibs = (varfunc*) GetProcAddress(hinstLib, "luaL_openlibs");
lua_pcall = (varfunc*)GetProcAddress(hinstLib, "lua_pcall");
lua_tolstring = (varfunc*)GetProcAddress(hinstLib, "lua_tolstring");
lua_setfield = (varfunc*)GetProcAddress(hinstLib, "lua_setfield");
lua_pushcclosure = (varfunc*)GetProcAddress(hinstLib, "lua_pushcclosure");
lua_createtable = (varfuncvoid*)GetProcAddress(hinstLib, "lua_createtable");
lua_pushstring = (varfuncvoid*)GetProcAddress(hinstLib, "lua_pushstring");
lua_rawseti = (varfuncvoid*)GetProcAddress(hinstLib, "lua_rawseti");
// If the function address is valid, call the function.
if (luaL_newstate && luaL_loadbuffer && luaL_openlibs && lua_pcall &&
lua_pushcclosure && lua_setfield && lua_tolstring &&
lua_createtable && lua_pushstring && lua_rawseti)
{
// OK, I don't do any error checking here, which COULD
// lead to bugs that are hard to find, but considered the simplicity
// of the whole process, it SHOULD be pretty unlikely to fail here
// but don't come back on me if it does...
void *L = luaL_newstate();
int i;
if (L!=NULL) {
lua_createtable(L,argc,0);
for (i=0;i<argc;i++) {
lua_pushstring(L,argv[i]);
lua_rawseti(L,-2,i+1);
}
lua_setfield(L,LUA_GLOBALSINDEX,"_ARG");
luaL_openlibs(L);
lua_pushcclosure(L,luafunc_mbox,0);
lua_setfield(L,LUA_GLOBALSINDEX,"_ERRMSG");
if (luaL_loadbuffer(L,luacode,strlen(luacode),"Initializer") == 0)
lua_pcall(L,0,0,0);
else
MessageBox(NULL,
TEXT("An unexpected error occured while loading the lua chunk."),
TEXT("Failed to start estrela"),
MB_OK|MB_ICONERROR);
} else
MessageBox(NULL,
TEXT("Couldn't initialize a luastate"),
TEXT("Failed to start estrela"),
MB_OK|MB_ICONERROR);
} else {
MessageBox(NULL,
TEXT("Could not load all functions that are supposed to be located in the lua5.1.dll\n"
"This is not supposed to be happening..."),
TEXT("Failed to start estrela"),
MB_OK|MB_ICONERROR);
}
// Free the DLL module.
FreeLibrary(hinstLib);
} else {
MessageBox(NULL,
TEXT("The lua5.1.dll could not be found or loaded, please check the working directory of the application.\n"),
TEXT("Failed to initialize estrela"),
MB_OK|MB_ICONERROR);
}
return 0;
}
// this is an extremly ugly quick and dirty hack...
// maybe it could be refactored to do some error catching and
// other things, but right now it does what it should...
// (providing a single exe file in our main directory without
// polluting it with all these dlls located in the /bin folder)
#ifdef __MINGW__ /* not sure if this is the *official* define */
#define _WIN32_WINNT 0x0502
#endif
#include <windows.h>
#include <winbase.h>
#include <stdlib.h>
#include <stdio.h>
/* some typedef functions - these are not matching exactly the
original definitions, but their signature is supposed to be
compatible
Currently 10 different functions are needed - each with different signatures... */
typedef void *voidfunc ();
typedef int *varfunc (void *L,...); // quick and dirty using the varargs
typedef void varfuncvoid (void *L,...);
// from lua.h
#define LUA_GLOBALSINDEX (-10002)
static voidfunc *luaL_newstate;
static varfunc *luaL_loadbuffer;
static varfunc *luaL_openlibs;
static varfunc *lua_pcall;
static varfunc *lua_pushcclosure;
static varfunc *lua_setfield;
static varfunc *lua_tolstring;
static varfuncvoid *lua_createtable;
static varfuncvoid *lua_pushstring;
static varfuncvoid *lua_rawseti;
static int luafunc_mbox (void *L)
{
const char *title = (const char*)lua_tolstring(L,1,NULL);
const char *msg = (const char*)lua_tolstring(L,2,NULL);
MessageBox(NULL,msg,title,MB_OK|MB_ICONERROR);
return 0;
}
static const char *luacode =
"local msg = _ERRMSG; _ERRMSG = nil "
"local arg = _ARG or {}; _ARG = nil "
"xpcall("
"function() "
"(loadfile 'src/main.lua')(unpack(arg)) end,"
"function(err) msg('Uncaught lua script exception',debug.traceback(err)) end)"
;
#if defined(_WIN32) && defined (_MSC_VER)
PCHAR* CommandLineToArgvA(PCHAR CmdLine,int* _argc)
{
PCHAR* argv;
PCHAR _argv;
size_t len;
ULONG argc;
CHAR a;
size_t i, j;
BOOLEAN in_QM;
BOOLEAN in_TEXT;
BOOLEAN in_SPACE;
len = strlen(CmdLine);
i = ((len+2)/2)*sizeof(PVOID) + sizeof(PVOID);
argv = (PCHAR*)GlobalAlloc(GMEM_FIXED,
i + (len+2)*sizeof(CHAR));
_argv = (PCHAR)(((PUCHAR)argv)+i);
argc = 0;
argv[argc] = _argv;
in_QM = 0;
in_TEXT = 0;
in_SPACE = 1;
i = 0;
j = 0;
while( a = CmdLine[i] ) {
if(in_QM) {
if(a == '\"') {
in_QM = 0;
} else {
_argv[j] = a;
j++;
}
} else {
switch(a) {
case '\"':
in_QM = 1;
in_TEXT = 1;
if(in_SPACE) {
argv[argc] = _argv+j;
argc++;
}
in_SPACE = 0;
break;
case ' ':
case '\t':
case '\n':
case '\r':
if(in_TEXT) {
_argv[j] = '\0';
j++;
}
in_TEXT = 0;
in_SPACE = 1;
break;
default:
in_TEXT = 1;
if(in_SPACE) {
argv[argc] = _argv+j;
argc++;
}
_argv[j] = a;
j++;
in_SPACE = 0;
break;
}
}
i++;
}
_argv[j] = '\0';
argv[argc] = NULL;
(*_argc) = argc;
return argv;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
int argc;
char ** argv = CommandLineToArgvA(GetCommandLineA(),&argc);
#else
int main (int argc, char *argv[])
{
#endif
HINSTANCE hinstLib;
char buffer[MAX_PATH],*file;
if (!GetFullPathName(argv[0],MAX_PATH,buffer,&file)) {
MessageBox(NULL,
TEXT("Couldn't find the correct working directory"),
TEXT("Failed to start estrela"),
MB_OK|MB_ICONERROR);
return 0;
}
if (file!=NULL)
*file = 0; // finish the string, I don't need the appname
//int i;
//for (i=0;i<argc; i++)
// printf("%d %s\n",i,argv[i]);
SetCurrentDirectory(buffer);
SetDllDirectory(".\\bin\\");
hinstLib = LoadLibrary("lua5.1.dll");
if (hinstLib != NULL)
{
luaL_newstate = (voidfunc*) GetProcAddress(hinstLib, "luaL_newstate");
luaL_loadbuffer = (varfunc*) GetProcAddress(hinstLib, "luaL_loadbuffer");
luaL_openlibs = (varfunc*) GetProcAddress(hinstLib, "luaL_openlibs");
lua_pcall = (varfunc*)GetProcAddress(hinstLib, "lua_pcall");
lua_tolstring = (varfunc*)GetProcAddress(hinstLib, "lua_tolstring");
lua_setfield = (varfunc*)GetProcAddress(hinstLib, "lua_setfield");
lua_pushcclosure = (varfunc*)GetProcAddress(hinstLib, "lua_pushcclosure");
lua_createtable = (varfuncvoid*)GetProcAddress(hinstLib, "lua_createtable");
lua_pushstring = (varfuncvoid*)GetProcAddress(hinstLib, "lua_pushstring");
lua_rawseti = (varfuncvoid*)GetProcAddress(hinstLib, "lua_rawseti");
// If the function address is valid, call the function.
if (luaL_newstate && luaL_loadbuffer && luaL_openlibs && lua_pcall &&
lua_pushcclosure && lua_setfield && lua_tolstring &&
lua_createtable && lua_pushstring && lua_rawseti)
{
// OK, I don't do any error checking here, which COULD
// lead to bugs that are hard to find, but considered the simplicity
// of the whole process, it SHOULD be pretty unlikely to fail here
// but don't come back on me if it does...
void *L = luaL_newstate();
int i;
if (L!=NULL) {
lua_createtable(L,argc,0);
for (i=0;i<argc;i++) {
lua_pushstring(L,argv[i]);
lua_rawseti(L,-2,i+1);
}
lua_setfield(L,LUA_GLOBALSINDEX,"_ARG");
luaL_openlibs(L);
lua_pushcclosure(L,luafunc_mbox,0);
lua_setfield(L,LUA_GLOBALSINDEX,"_ERRMSG");
if (luaL_loadbuffer(L,luacode,strlen(luacode),"Initializer") == 0)
lua_pcall(L,0,0,0);
else
MessageBox(NULL,
TEXT("An unexpected error occured while loading the lua chunk."),
TEXT("Failed to start estrela"),
MB_OK|MB_ICONERROR);
} else
MessageBox(NULL,
TEXT("Couldn't initialize a luastate"),
TEXT("Failed to start estrela"),
MB_OK|MB_ICONERROR);
} else {
MessageBox(NULL,
TEXT("Could not load all functions that are supposed to be located in the lua5.1.dll\n"
"This is not supposed to be happening..."),
TEXT("Failed to start estrela"),
MB_OK|MB_ICONERROR);
}
// Free the DLL module.
FreeLibrary(hinstLib);
} else {
MessageBox(NULL,
TEXT("The lua5.1.dll could not be found or loaded, please check the working directory of the application.\n"),
TEXT("Failed to initialize estrela"),
MB_OK|MB_ICONERROR);
}
return 0;
}

View File

@@ -1 +0,0 @@
git://estrelaeditor.git.sourceforge.net/gitroot/estrelaeditor/estrelaeditor

View File

@@ -1,12 +1,12 @@
return {
name = "Estrela Editor",
description = "Estrela Editor as run target (IDE development)",
api = {"wxwidgets","baselib"},
frun = function(self,wfilename)
local cmd = ide.editorFilename and '"'..ide.editorFilename..'" '..(wfilename and wfilename:GetFullPath() or "")..' -cfg "singleinstance=false;"' or nil
CommandLineRun(cmd,nil,false,true)
end,
fprojdir = function(self,wfilename)
return wfilename:GetPath(wx.wxPATH_GET_VOLUME)
end,
}
return {
name = "Estrela Editor",
description = "Estrela Editor as run target (IDE development)",
api = {"wxwidgets","baselib"},
frun = function(self,wfilename)
local cmd = ide.editorFilename and '"'..ide.editorFilename..'" '..(wfilename and wfilename:GetFullPath() or "")..' -cfg "singleinstance=false;"' or nil
CommandLineRun(cmd,nil,false,true)
end,
fprojdir = function(self,wfilename)
return wfilename:GetPath(wx.wxPATH_GET_VOLUME)
end,
}

View File

@@ -1,21 +1,15 @@
return {
name = "Estrela Shell",
description = "Estrela Lua Shell",
api = {"wxwidgets","baselib"},
frun = function(self,wfilename)
-- set shellbox for focus
local bottomnotebook = ide.frame.vsplitter.splitter.bottomnotebook
bottomnotebook:SetSelection(1)
if ide.frame.menuBar:IsChecked(ID_CLEAROUTPUT) then
local shellLog = bottomnotebook.shellbox.output
shellLog:SetReadOnly(false)
shellLog:ClearAll()
shellLog:SetReadOnly(true)
end
ShellExecuteCode(nil,wfilename)
end,
fprojdir = function(self,wfilename)
return wfilename:GetPath(wx.wxPATH_GET_VOLUME)
end,
}
return {
name = "Estrela Shell",
description = "Estrela Lua Shell",
api = {"wxwidgets","baselib"},
frun = function(self,wfilename)
-- set shellbox for focus
local bottomnotebook = ide.frame.bottomnotebook
bottomnotebook:SetSelection(1)
ShellExecuteFile(wfilename)
end,
fprojdir = function(self,wfilename)
return wfilename:GetPath(wx.wxPATH_GET_VOLUME)
end,
}

View File

@@ -1,19 +1,22 @@
return {
name = "Lua",
description = "Commandline Lua interpreter",
api = {"wxwidgets","baselib"},
frun = function(self,wfilename,script)
local mainpath = ide.editorFilename:gsub("[^/\\]+$","")
local filepath = wfilename:GetFullPath()
if not script then script = ([[dofile '%s']]):format(filepath:gsub("\\","/")) end
local code = ([[xpcall(function() %s end,function(err) print(debug.traceback(err)) end)]]):format(script)
local cmd = '"'..mainpath..'/bin/lua.exe" -e "'..code..'"'
CommandLineRun(cmd,self:fworkdir(wfilename),true,false)
end,
fprojdir = function(self,wfilename)
return ide.config.path.projectdir
end,
fworkdir = function (self,wfilename)
return wfilename:GetPath(wx.wxPATH_GET_VOLUME)
end,
}
return {
name = "Lua",
description = "Commandline Lua interpreter",
api = {"wxwidgets","baselib"},
frun = function(self,wfilename)
local mainpath = ide.editorFilename:gsub("[^/\\]+$","")
local filepath = wfilename:GetFullPath()
local code = ([[
xpcall(function() dofile '%s' end,
function(err) print(debug.traceback(err)) end)
]]):format(filepath:gsub("\\","/"))
local cmd = '"'..mainpath..'/bin/lua.exe" -e "'..code..'"'
CommandLineRun(cmd,self:fworkdir(wfilename),true,false)
end,
fprojdir = function(self,wfilename)
return wfilename:GetPath(wx.wxPATH_GET_VOLUME)
end,
fworkdir = function (self,wfilename)
return ide.config.path.projectdir and ide.config.path.projectdir:len()>0 and
ide.config.path.projectdir
end,
}

35
interpreters/luadeb.lua Normal file
View File

@@ -0,0 +1,35 @@
return {
name = "Lua Debug",
description = "Commandline Lua interpreter",
api = {"wxwidgets","baselib"},
frun = function(self,wfilename,rundebug)
local mainpath = string.gsub(ide.editorFilename:gsub("[^/\\]+$",""),"\\","/")
local filepath = string.gsub(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';"..
"require('mobdebug').loop('" .. wx.wxGetHostName().."',"..ide.debugger.portnumber..")")
else
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.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)
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,
}

View File

@@ -1,27 +1,33 @@
return {
name = "Luxinia",
description = "Luxinia project",
api = {"luxiniaapi","baselib"},
fcmdline = function(self,wfilename)
local projdir = ide.config.path.projectdir
local endstr = projdir and projdir:len()>0
and " -p "..projdir or ""
local fname = wfilename:GetFullName()
endstr = endstr..(fname and (" -t "..fname) or "")
local cmd = ide.config.path.luxinia..'luxinia.exe --nologo'..endstr
CommandLineRun(cmd,ide.config.path.luxinia,true,true)
end,
fprojdir = function(self,wfilename)
local path = GetPathWithSep(wfilename)
fname = wx.wxFileName(path)
while ((not wx.wxFileExists(path.."main.lua")) and (fname:GetDirCount() > 0)) do
fname:RemoveDir(fname:GetDirCount()-1)
path = GetPathWithSep(fname)
end
return path:sub(0,-2)
end,
}
if (not(ide.config.path.luxinia and
wx.wxFileExists(ide.config.path.luxinia..'luxinia.exe'))) then
return
end
return {
name = "Luxinia",
description = "Luxinia project",
api = {"luxiniaapi","baselib"},
frun = function(self,wfilename,withdebug)
local projdir = ide.config.path.projectdir
local endstr = (projdir and projdir:len()>0
and " -p "..projdir or "")
local fname = wfilename:GetFullName()
endstr = endstr..(fname and (" -t "..fname) or "")
local cmd = 'luxinia.exe --nologo'..endstr
CommandLineRun(cmd,ide.config.path.luxinia,true,true)
end,
fuid = function(self,wfilename) return "luxinia "..(ide.config.path.projectdir or "") end,
fprojdir = function(self,wfilename)
local path = GetPathWithSep(wfilename)
fname = wx.wxFileName(path)
while ((not wx.wxFileExists(path.."main.lua")) and (fname:GetDirCount() > 0)) do
fname:RemoveDir(fname:GetDirCount()-1)
path = GetPathWithSep(fname)
end
return path:sub(0,-2)
end,
}

View File

@@ -1,60 +1,97 @@
if (not(ide.config.path.luxinia2 and
wx.wxFileExists(ide.config.path.luxinia2..'luajit.exe'))) then
return
end
return {
name = "Luxinia2",
description = "Luxinia2",
api = {"baselib","cg30","cggl30","glfw3","glewgl","assimp20","luxmath","luxgfx","luxscene","luajit2",},
finitclient = function(self)
if (not CommandLineRunning(self:fuid(wfilename))) then return end
local init = dofile(ide.config.path.luxinia2.."/../comserver/client.lua")
local fenv = {}
setmetatable(fenv,{__index = _G})
fenv.print = function(...) DisplayOutput(...); DisplayOutput("\n"); end
setfenv(init,fenv)
local client = init()
self.fclient = client
return client
end,
frun = function(self,wfilename)
local luxdir = ide.config.path.luxinia2
local projdir = ide.config.path.projectdir
assert(projdir and projdir:len()>0,"no project directory")
local args = " -e "..projdir.."/main.lua"
if (CommandLineRunning(self:fuid(wfilename))) then
if (not self.fclient) then
self:finitclient()
end
-- try to communicate with server
self.fclient("dofile([["..wfilename:GetFullPath().."]])")
return
end
self.fclient = nil
local fname = wfilename:GetFullName()
args = args..(fname and (" -f "..fname) or "")
local jitargs = ide.config.luxinia2jitargs
jitargs = jitargs or ""
local cmd = luxdir..'/luajit.exe '..jitargs..' ../main.lua -s'..args
if(CommandLineRun(cmd,ide.config.path.luxinia2,true,true,nil,self:fuid(wfilename),
function() ShellSupportRemote(nil) end)) then return end
local client = self:finitclient()
ShellSupportRemote(client,self:fuid(wfilename))
end,
fuid = function(self,wfilename) return "luxinia2 "..(ide.config.path.projectdir or "") end,
fprojdir = function(self,wfilename)
local path = GetPathWithSep(wfilename)
filepath = wx.wxFileName(path)
while ((not wx.wxFileExists(path.."main.lua")) and (filepath:GetDirCount() > 0)) do
filepath:RemoveDir(filepath:GetDirCount()-1)
path = GetPathWithSep(filepath)
end
return path:sub(0,-2)
end,
}
name = "Luxinia2",
description = "Luxinia2",
api = {"baselib","cg30","cggl30","glfw","glewgl","assimp20","luxmath","luxgfx","luxscene","luajit2",},
finitclient = function(self)
if (not CommandLineRunning(self:fuid(wfilename))) then return end
local init = dofile(ide.config.path.luxinia2.."/../comserver/client.lua")
local fenv = {}
setmetatable(fenv,{__index = _G})
fenv.print = function(...) DisplayOutput(...); DisplayOutput("\n"); end
setfenv(init,fenv)
local client = init()
self.fclient = client
return client
end,
frun = function(self,wfilename,rundebug)
local luxdir = ide.config.path.luxinia2
local projdir = ide.config.path.projectdir
assert(projdir and projdir:len()>0,"no project directory")
local basedir = luxdir
local startfile = projdir.."/main.lua"
local startargs = " -e "..startfile
if (CommandLineRunning(self:fuid(wfilename))) then
if (not self.fclient) then
self:finitclient()
end
-- try to communicate with server
self.fclient("dofile([["..wfilename:GetFullPath().."]])")
return
end
self.fclient = nil
local fname = wfilename:GetFullName()
local args = (fname and (" -f "..fname) or "")
if rundebug then
DebuggerAttachDefault({
basedir=basedir,
startfile=startfile,
run=true, noshell=true,}
)
local editorDir = string.gsub(ide.editorFilename:gsub("[^/\\]+$",""),"\\","/")
script = ""..
"package.path=package.path..';"..editorDir.."lualibs/?/?.lua';"..
"io.stdout:setvbuf('no'); require('mobdebug').start('" .. wx.wxGetHostName().."',"..ide.debugger.portnumber..")"
args = args..' -es "'..script..'"'..startargs
else
args = " -s "..args..startargs
end
local jitargs = ide.config.luxinia2jitargs
jitargs = jitargs or ""
local cmd = 'luajit.exe '..jitargs..' ../main.lua '..args
local pid = CommandLineRun(cmd,ide.config.path.luxinia2,true,true,nil,self:fuid(wfilename),
function()
ShellSupportRemote(nil)
if (rundebug) then
DebuggerStop()
end
end)
if(not pid) then return end
if not rundebug then
local client = self:finitclient()
ShellSupportRemote(client,self:fuid(wfilename))
end
return pid
end,
fuid = function(self,wfilename) return "luxinia2 "..(ide.config.path.projectdir or "") end,
fprojdir = function(self,wfilename)
local path = GetPathWithSep(wfilename)
filepath = wx.wxFileName(path)
while ((not wx.wxFileExists(path.."main.lua")) and (filepath:GetDirCount() > 0)) do
filepath:RemoveDir(filepath:GetDirCount()-1)
path = GetPathWithSep(filepath)
end
return path:sub(0,-2)
end,
hasdebugger = true,
}

1271
lualibs/metalua/compile.lua Normal file

File diff suppressed because it is too large Load Diff

756
lualibs/metalua/gg.lua Normal file
View File

@@ -0,0 +1,756 @@
----------------------------------------------------------------------
-- Metalua.
--
-- Summary: parser generator. Collection of higher order functors,
-- which allow to build and combine parsers. Relies on a lexer
-- that supports the same API as the one exposed in mll.lua.
--
----------------------------------------------------------------------
--
-- Copyright (c) 2006-2008, Fabien Fleutot <metalua@gmail.com>.
--
-- This software is released under the MIT Licence, see licence.txt
-- for details.
--
----------------------------------------------------------------------
--------------------------------------------------------------------------------
--
-- Exported API:
--
-- Parser generators:
-- * [gg.sequence()]
-- * [gg.multisequence()]
-- * [gg.expr()]
-- * [gg.list()]
-- * [gg.onkeyword()]
-- * [gg.optkeyword()]
--
-- Other functions:
-- * [gg.parse_error()]
-- * [gg.make_parser()]
-- * [gg.is_parser()]
--
--------------------------------------------------------------------------------
module("gg", package.seeall)
-------------------------------------------------------------------------------
-- parser metatable, which maps __call to method parse, and adds some
-- error tracing boilerplate.
-------------------------------------------------------------------------------
local parser_metatable = { }
function parser_metatable.__call (parser, lx, ...)
--printf ("Call parser %q of type %q", parser.name or "?", parser.kind)
if mlc.metabugs then
return parser:parse (lx, ...)
--local x = parser:parse (lx, ...)
--printf ("Result of parser %q: %s",
-- parser.name or "?",
-- _G.table.tostring(x, "nohash", 80))
--return x
else
local li = lx:lineinfo_right() or { "?", "?", "?", "?" }
local status, ast = pcall (parser.parse, parser, lx, ...)
if status then return ast else
-- Try to replace the gg.lua location, in the error msg, with
-- the place where the current parser started handling the
-- lexstream.
-- Since the error is rethrown, these places are stacked.
error (string.format ("%s\n - (l.%s, c.%s, k.%s) in parser %s",
ast :strmatch "gg.lua:%d+: (.*)" or ast,
li[1], li[2], li[3], parser.name or parser.kind))
end
end
end
-------------------------------------------------------------------------------
-- Turn a table into a parser, mainly by setting the metatable.
-------------------------------------------------------------------------------
function make_parser(kind, p)
p.kind = kind
if not p.transformers then p.transformers = { } end
function p.transformers:add (x)
table.insert (self, x)
end
setmetatable (p, parser_metatable)
return p
end
-------------------------------------------------------------------------------
-- Return true iff [x] is a parser.
-- If it's a gg-generated parser, return the name of its kind.
-------------------------------------------------------------------------------
function is_parser (x)
return type(x)=="function" or getmetatable(x)==parser_metatable and x.kind
end
-------------------------------------------------------------------------------
-- Parse a sequence, without applying builder nor transformers
-------------------------------------------------------------------------------
local function raw_parse_sequence (lx, p)
local r = { }
for i=1, #p do
e=p[i]
if type(e) == "string" then
if not lx:is_keyword (lx:next(), e) then
parse_error (lx, "A keyword was expected, probably `%s'.", e) end
elseif is_parser (e) then
table.insert (r, e (lx))
else
gg.parse_error (lx,"Sequence `%s': element #%i is neither a string "..
"nor a parser: %s",
p.name, i, table.tostring(e))
end
end
return r
end
-------------------------------------------------------------------------------
-- Parse a multisequence, without applying multisequence transformers.
-- The sequences are completely parsed.
-------------------------------------------------------------------------------
local function raw_parse_multisequence (lx, sequence_table, default)
local seq_parser = sequence_table[lx:is_keyword(lx:peek())]
if seq_parser then return seq_parser (lx)
elseif default then return default (lx)
else return false end
end
-------------------------------------------------------------------------------
-- Applies all transformers listed in parser on ast.
-------------------------------------------------------------------------------
local function transform (ast, parser, fli, lli)
if parser.transformers then
for _, t in ipairs (parser.transformers) do ast = t(ast) or ast end
end
if type(ast) == 'table'then
local ali = ast.lineinfo
if not ali or ali.first~=fli or ali.last~=lli then
ast.lineinfo = { first = fli, last = lli }
end
end
return ast
end
-------------------------------------------------------------------------------
-- Generate a tracable parsing error (not implemented yet)
-------------------------------------------------------------------------------
function parse_error(lx, fmt, ...)
local li = lx:lineinfo_left() or {-1,-1,-1, "<unknown file>"}
local msg = string.format("line %i, char %i: "..fmt, li[1], li[2], ...)
local src = lx.src
if li[3]>0 and src then
local i, j = li[3], li[3]
while src:sub(i,i) ~= '\n' and i>=0 do i=i-1 end
while src:sub(j,j) ~= '\n' and j<=#src do j=j+1 end
local srcline = src:sub (i+1, j-1)
local idx = string.rep (" ", li[2]).."^"
msg = string.format("%s\n>>> %s\n>>> %s", msg, srcline, idx)
end
error(msg)
end
-------------------------------------------------------------------------------
--
-- Sequence parser generator
--
-------------------------------------------------------------------------------
-- Input fields:
--
-- * [builder]: how to build an AST out of sequence parts. let [x] be the list
-- of subparser results (keywords are simply omitted). [builder] can be:
-- - [nil], in which case the result of parsing is simply [x]
-- - a string, which is then put as a tag on [x]
-- - a function, which takes [x] as a parameter and returns an AST.
--
-- * [name]: the name of the parser. Used for debug messages
--
-- * [transformers]: a list of AST->AST functions, applied in order on ASTs
-- returned by the parser.
--
-- * Table-part entries corresponds to keywords (strings) and subparsers
-- (function and callable objects).
--
-- After creation, the following fields are added:
-- * [parse] the parsing function lexer->AST
-- * [kind] == "sequence"
-- * [name] is set, if it wasn't in the input.
--
-------------------------------------------------------------------------------
function sequence (p)
make_parser ("sequence", p)
-------------------------------------------------------------------
-- Parsing method
-------------------------------------------------------------------
function p:parse (lx)
-- Raw parsing:
local fli = lx:lineinfo_right()
local seq = raw_parse_sequence (lx, self)
local lli = lx:lineinfo_left()
-- Builder application:
local builder, tb = self.builder, type (self.builder)
if tb == "string" then seq.tag = builder
elseif tb == "function" or builder and builder.__call then seq = builder(seq)
elseif builder == nil then -- nothing
else error ("Invalid builder of type "..tb.." in sequence") end
seq = transform (seq, self, fli, lli)
assert (not seq or seq.lineinfo)
return seq
end
-------------------------------------------------------------------
-- Construction
-------------------------------------------------------------------
-- Try to build a proper name
if p.name then
-- don't touch existing name
elseif type(p[1])=="string" then -- find name based on 1st keyword
if #p==1 then p.name=p[1]
elseif type(p[#p])=="string" then
p.name = p[1] .. " ... " .. p[#p]
else p.name = p[1] .. " ..." end
else -- can't find a decent name
p.name = "<anonymous>"
end
return p
end --</sequence>
-------------------------------------------------------------------------------
--
-- Multiple, keyword-driven, sequence parser generator
--
-------------------------------------------------------------------------------
-- in [p], useful fields are:
--
-- * [transformers]: as usual
--
-- * [name]: as usual
--
-- * Table-part entries must be sequence parsers, or tables which can
-- be turned into a sequence parser by [gg.sequence]. These
-- sequences must start with a keyword, and this initial keyword
-- must be different for each sequence. The table-part entries will
-- be removed after [gg.multisequence] returns.
--
-- * [default]: the parser to run if the next keyword in the lexer is
-- none of the registered initial keywords. If there's no default
-- parser and no suitable initial keyword, the multisequence parser
-- simply returns [false].
--
-- After creation, the following fields are added:
--
-- * [parse] the parsing function lexer->AST
--
-- * [sequences] the table of sequences, indexed by initial keywords.
--
-- * [add] method takes a sequence parser or a config table for
-- [gg.sequence], and adds/replaces the corresponding sequence
-- parser. If the keyword was already used, the former sequence is
-- removed and a warning is issued.
--
-- * [get] method returns a sequence by its initial keyword
--
-- * [kind] == "multisequence"
--
-------------------------------------------------------------------------------
function multisequence (p)
make_parser ("multisequence", p)
-------------------------------------------------------------------
-- Add a sequence (might be just a config table for [gg.sequence])
-------------------------------------------------------------------
function p:add (s)
-- compile if necessary:
local keyword = type(s)=='table' and s[1]
if type(s)=='table' and not is_parser(s) then sequence(s) end
if is_parser(s)~='sequence' or type(keyword)~='string' then
if self.default then -- two defaults
error ("In a multisequence parser, all but one sequences "..
"must start with a keyword")
else self.default = s end -- first default
elseif self.sequences[keyword] then -- duplicate keyword
eprintf (" *** Warning: keyword %q overloaded in multisequence ***",
keyword)
self.sequences[keyword] = s
else -- newly caught keyword
self.sequences[keyword] = s
end
end -- </multisequence.add>
-------------------------------------------------------------------
-- Get the sequence starting with this keyword. [kw :: string]
-------------------------------------------------------------------
function p:get (kw) return self.sequences [kw] end
-------------------------------------------------------------------
-- Remove the sequence starting with keyword [kw :: string]
-------------------------------------------------------------------
function p:del (kw)
if not self.sequences[kw] then
eprintf("*** Warning: trying to delete sequence starting "..
"with %q from a multisequence having no such "..
"entry ***", kw) end
local removed = self.sequences[kw]
self.sequences[kw] = nil
return removed
end
-------------------------------------------------------------------
-- Parsing method
-------------------------------------------------------------------
function p:parse (lx)
local fli = lx:lineinfo_right()
local x = raw_parse_multisequence (lx, self.sequences, self.default)
local lli = lx:lineinfo_left()
return transform (x, self, fli, lli)
end
-------------------------------------------------------------------
-- Construction
-------------------------------------------------------------------
-- Register the sequences passed to the constructor. They're going
-- from the array part of the parser to the hash part of field
-- [sequences]
p.sequences = { }
for i=1, #p do p:add (p[i]); p[i] = nil end
-- FIXME: why is this commented out?
--if p.default and not is_parser(p.default) then sequence(p.default) end
return p
end --</multisequence>
-------------------------------------------------------------------------------
--
-- Expression parser generator
--
-------------------------------------------------------------------------------
--
-- Expression configuration relies on three tables: [prefix], [infix]
-- and [suffix]. Moreover, the primary parser can be replaced by a
-- table: in this case the [primary] table will be passed to
-- [gg.multisequence] to create a parser.
--
-- Each of these tables is a modified multisequence parser: the
-- differences with respect to regular multisequence config tables are:
--
-- * the builder takes specific parameters:
-- - for [prefix], it takes the result of the prefix sequence parser,
-- and the prefixed expression
-- - for [infix], it takes the left-hand-side expression, the results
-- of the infix sequence parser, and the right-hand-side expression.
-- - for [suffix], it takes the suffixed expression, and theresult
-- of the suffix sequence parser.
--
-- * the default field is a list, with parameters:
-- - [parser] the raw parsing function
-- - [transformers], as usual
-- - [prec], the operator's precedence
-- - [assoc] for [infix] table, the operator's associativity, which
-- can be "left", "right" or "flat" (default to left)
--
-- In [p], useful fields are:
-- * [transformers]: as usual
-- * [name]: as usual
-- * [primary]: the atomic expression parser, or a multisequence config
-- table (mandatory)
-- * [prefix]: prefix operators config table, see above.
-- * [infix]: infix operators config table, see above.
-- * [suffix]: suffix operators config table, see above.
--
-- After creation, these fields are added:
-- * [kind] == "expr"
-- * [parse] as usual
-- * each table is turned into a multisequence, and therefore has an
-- [add] method
--
-------------------------------------------------------------------------------
function expr (p)
make_parser ("expr", p)
-------------------------------------------------------------------
-- parser method.
-- In addition to the lexer, it takes an optional precedence:
-- it won't read expressions whose precedence is lower or equal
-- to [prec].
-------------------------------------------------------------------
function p:parse (lx, prec)
prec = prec or 0
------------------------------------------------------
-- Extract the right parser and the corresponding
-- options table, for (pre|in|suff)fix operators.
-- Options include prec, assoc, transformers.
------------------------------------------------------
local function get_parser_info (tab)
local p2 = tab:get (lx:is_keyword (lx:peek()))
if p2 then -- keyword-based sequence found
local function parser(lx) return raw_parse_sequence(lx, p2) end
return parser, p2
else -- Got to use the default parser
local d = tab.default
if d then return d.parse or d.parser, d
else return false, false end
end
end
------------------------------------------------------
-- Look for a prefix sequence. Multiple prefixes are
-- handled through the recursive [p.parse] call.
-- Notice the double-transform: one for the primary
-- expr, and one for the one with the prefix op.
------------------------------------------------------
local function handle_prefix ()
local fli = lx:lineinfo_right()
local p2_func, p2 = get_parser_info (self.prefix)
local op = p2_func and p2_func (lx)
if op then -- Keyword-based sequence found
local ili = lx:lineinfo_right() -- Intermediate LineInfo
local e = p2.builder (op, self:parse (lx, p2.prec))
local lli = lx:lineinfo_left()
return transform (transform (e, p2, ili, lli), self, fli, lli)
else -- No prefix found, get a primary expression
local e = self.primary(lx)
local lli = lx:lineinfo_left()
return transform (e, self, fli, lli)
end
end --</expr.parse.handle_prefix>
------------------------------------------------------
-- Look for an infix sequence+right-hand-side operand.
-- Return the whole binary expression result,
-- or false if no operator was found.
------------------------------------------------------
local function handle_infix (e)
local p2_func, p2 = get_parser_info (self.infix)
if not p2 then return false end
-----------------------------------------
-- Handle flattening operators: gather all operands
-- of the series in [list]; when a different operator
-- is found, stop, build from [list], [transform] and
-- return.
-----------------------------------------
if (not p2.prec or p2.prec>prec) and p2.assoc=="flat" then
local fli = lx:lineinfo_right()
local pflat, list = p2, { e }
repeat
local op = p2_func(lx)
if not op then break end
table.insert (list, self:parse (lx, p2.prec))
local _ -- We only care about checking that p2==pflat
_, p2 = get_parser_info (self.infix)
until p2 ~= pflat
local e2 = pflat.builder (list)
local lli = lx:lineinfo_left()
return transform (transform (e2, pflat, fli, lli), self, fli, lli)
-----------------------------------------
-- Handle regular infix operators: [e] the LHS is known,
-- just gather the operator and [e2] the RHS.
-- Result goes in [e3].
-----------------------------------------
elseif p2.prec and p2.prec>prec or
p2.prec==prec and p2.assoc=="right" then
local fli = e.lineinfo.first -- lx:lineinfo_right()
local op = p2_func(lx)
if not op then return false end
local e2 = self:parse (lx, p2.prec)
local e3 = p2.builder (e, op, e2)
local lli = lx:lineinfo_left()
return transform (transform (e3, p2, fli, lli), self, fli, lli)
-----------------------------------------
-- Check for non-associative operators, and complain if applicable.
-----------------------------------------
elseif p2.assoc=="none" and p2.prec==prec then
parse_error (lx, "non-associative operator!")
-----------------------------------------
-- No infix operator suitable at that precedence
-----------------------------------------
else return false end
end --</expr.parse.handle_infix>
------------------------------------------------------
-- Look for a suffix sequence.
-- Return the result of suffix operator on [e],
-- or false if no operator was found.
------------------------------------------------------
local function handle_suffix (e)
-- FIXME bad fli, must take e.lineinfo.first
local p2_func, p2 = get_parser_info (self.suffix)
if not p2 then return false end
if not p2.prec or p2.prec>=prec then
--local fli = lx:lineinfo_right()
local fli = e.lineinfo.first
local op = p2_func(lx)
if not op then return false end
local lli = lx:lineinfo_left()
e = p2.builder (e, op)
e = transform (transform (e, p2, fli, lli), self, fli, lli)
return e
end
return false
end --</expr.parse.handle_suffix>
------------------------------------------------------
-- Parser body: read suffix and (infix+operand)
-- extensions as long as we're able to fetch more at
-- this precedence level.
------------------------------------------------------
local e = handle_prefix()
repeat
local x = handle_suffix (e); e = x or e
local y = handle_infix (e); e = y or e
until not (x or y)
-- No transform: it already happened in operators handling
return e
end --</expr.parse>
-------------------------------------------------------------------
-- Construction
-------------------------------------------------------------------
if not p.primary then p.primary=p[1]; p[1]=nil end
for _, t in ipairs{ "primary", "prefix", "infix", "suffix" } do
if not p[t] then p[t] = { } end
if not is_parser(p[t]) then multisequence(p[t]) end
end
function p:add(...) return self.primary:add(...) end
return p
end --</expr>
-------------------------------------------------------------------------------
--
-- List parser generator
--
-------------------------------------------------------------------------------
-- In [p], the following fields can be provided in input:
--
-- * [builder]: takes list of subparser results, returns AST
-- * [transformers]: as usual
-- * [name]: as usual
--
-- * [terminators]: list of strings representing the keywords which
-- might mark the end of the list. When non-empty, the list is
-- allowed to be empty. A string is treated as a single-element
-- table, whose element is that string, e.g. ["do"] is the same as
-- [{"do"}].
--
-- * [separators]: list of strings representing the keywords which can
-- separate elements of the list. When non-empty, one of these
-- keyword has to be found between each element. Lack of a separator
-- indicates the end of the list. A string is treated as a
-- single-element table, whose element is that string, e.g. ["do"]
-- is the same as [{"do"}]. If [terminators] is empty/nil, then
-- [separators] has to be non-empty.
--
-- After creation, the following fields are added:
-- * [parse] the parsing function lexer->AST
-- * [kind] == "list"
--
-------------------------------------------------------------------------------
function list (p)
make_parser ("list", p)
-------------------------------------------------------------------
-- Parsing method
-------------------------------------------------------------------
function p:parse (lx)
------------------------------------------------------
-- Used to quickly check whether there's a terminator
-- or a separator immediately ahead
------------------------------------------------------
local function peek_is_in (keywords)
return keywords and lx:is_keyword(lx:peek(), unpack(keywords)) end
local x = { }
local fli = lx:lineinfo_right()
-- if there's a terminator to start with, don't bother trying
if not peek_is_in (self.terminators) then
repeat table.insert (x, self.primary (lx)) -- read one element
until
-- First reason to stop: There's a separator list specified,
-- and next token isn't one. Otherwise, consume it with [lx:next()]
self.separators and not(peek_is_in (self.separators) and lx:next()) or
-- Other reason to stop: terminator token ahead
peek_is_in (self.terminators) or
-- Last reason: end of file reached
lx:peek().tag=="Eof"
end
local lli = lx:lineinfo_left()
-- Apply the builder. It can be a string, or a callable value,
-- or simply nothing.
local b = self.builder
if b then
if type(b)=="string" then x.tag = b -- b is a string, use it as a tag
elseif type(b)=="function" then x=b(x)
else
local bmt = getmetatable(b)
if bmt and bmt.__call then x=b(x) end
end
end
return transform (x, self, fli, lli)
end --</list.parse>
-------------------------------------------------------------------
-- Construction
-------------------------------------------------------------------
if not p.primary then p.primary = p[1]; p[1] = nil end
if type(p.terminators) == "string" then p.terminators = { p.terminators }
elseif p.terminators and #p.terminators == 0 then p.terminators = nil end
if type(p.separators) == "string" then p.separators = { p.separators }
elseif p.separators and #p.separators == 0 then p.separators = nil end
return p
end --</list>
-------------------------------------------------------------------------------
--
-- Keyword-conditionned parser generator
--
-------------------------------------------------------------------------------
--
-- Only apply a parser if a given keyword is found. The result of
-- [gg.onkeyword] parser is the result of the subparser (modulo
-- [transformers] applications).
--
-- lineinfo: the keyword is *not* included in the boundaries of the
-- resulting lineinfo. A review of all usages of gg.onkeyword() in the
-- implementation of metalua has shown that it was the appropriate choice
-- in every case.
--
-- Input fields:
--
-- * [name]: as usual
--
-- * [transformers]: as usual
--
-- * [peek]: if non-nil, the conditionning keyword is left in the lexeme
-- stream instead of being consumed.
--
-- * [primary]: the subparser.
--
-- * [keywords]: list of strings representing triggering keywords.
--
-- * Table-part entries can contain strings, and/or exactly one parser.
-- Strings are put in [keywords], and the parser is put in [primary].
--
-- After the call, the following fields will be set:
--
-- * [parse] the parsing method
-- * [kind] == "onkeyword"
-- * [primary]
-- * [keywords]
--
-------------------------------------------------------------------------------
function onkeyword (p)
make_parser ("onkeyword", p)
-------------------------------------------------------------------
-- Parsing method
-------------------------------------------------------------------
function p:parse(lx)
if lx:is_keyword (lx:peek(), unpack(self.keywords)) then
--local fli = lx:lineinfo_right()
if not self.peek then lx:next() end
local content = self.primary (lx)
--local lli = lx:lineinfo_left()
local fli, lli = content.lineinfo.first, content.lineinfo.last
return transform (content, p, fli, lli)
else return false end
end
-------------------------------------------------------------------
-- Construction
-------------------------------------------------------------------
if not p.keywords then p.keywords = { } end
for _, x in ipairs(p) do
if type(x)=="string" then table.insert (p.keywords, x)
else assert (not p.primary and is_parser (x)); p.primary = x end
end
if not next (p.keywords) then
eprintf("Warning, no keyword to trigger gg.onkeyword") end
assert (p.primary, 'no primary parser in gg.onkeyword')
return p
end --</onkeyword>
-------------------------------------------------------------------------------
--
-- Optional keyword consummer pseudo-parser generator
--
-------------------------------------------------------------------------------
--
-- This doesn't return a real parser, just a function. That function parses
-- one of the keywords passed as parameters, and returns it. It returns
-- [false] if no matching keyword is found.
--
-- Notice that tokens returned by lexer already carry lineinfo, therefore
-- there's no need to add them, as done usually through transform() calls.
-------------------------------------------------------------------------------
function optkeyword (...)
local args = {...}
if type (args[1]) == "table" then
assert (#args == 1)
args = args[1]
end
for _, v in ipairs(args) do assert (type(v)=="string") end
return function (lx)
local x = lx:is_keyword (lx:peek(), unpack (args))
if x then lx:next(); return x
else return false end
end
end
-------------------------------------------------------------------------------
--
-- Run a parser with a special lexer
--
-------------------------------------------------------------------------------
--
-- This doesn't return a real parser, just a function.
-- First argument is the lexer class to be used with the parser,
-- 2nd is the parser itself.
-- The resulting parser returns whatever the argument parser does.
--
-------------------------------------------------------------------------------
function with_lexer(new_lexer, parser)
-------------------------------------------------------------------
-- Most gg functions take their parameters in a table, so it's
-- better to silently accept when with_lexer{ } is called with
-- its arguments in a list:
-------------------------------------------------------------------
if not parser and #new_lexer==2 and type(new_lexer[1])=='table' then
return with_lexer(unpack(new_lexer))
end
-------------------------------------------------------------------
-- Save the current lexer, switch it for the new one, run the parser,
-- restore the previous lexer, even if the parser caused an error.
-------------------------------------------------------------------
return function (lx)
local old_lexer = getmetatable(lx)
lx:sync()
setmetatable(lx, new_lexer)
local status, result = pcall(parser, lx)
lx:sync()
setmetatable(lx, old_lexer)
if status then return result else error(result) end
end
end

1034
lualibs/metalua/lcode.lua Normal file

File diff suppressed because it is too large Load Diff

441
lualibs/metalua/ldump.lua Normal file
View File

@@ -0,0 +1,441 @@
----------------------------------------------------------------------
--
-- WARNING! You're entering a hackish area, proceed at your own risks!
--
-- This code results from the borrowing, then ruthless abuse, of
-- Yueliang's implementation of Lua 5.0 compiler. I claim
-- responsibility for all of the ugly, dirty stuff that you might spot
-- in it.
--
-- Eventually, this code will be rewritten, either in Lua or more
-- probably in C. Meanwhile, if you're interested into digging
-- metalua's sources, this is not the best part to invest your time
-- on.
--
-- End of warning.
--
----------------------------------------------------------------------
--[[--------------------------------------------------------------------
$Id$
ldump.lua
Save bytecodes in Lua
This file is part of Yueliang.
Copyright (c) 2005 Kein-Hong Man <khman@users.sf.net>
The COPYRIGHT file describes the conditions
under which this software may be distributed.
------------------------------------------------------------------------
[FF] Slightly modified, mainly to produce Lua 5.1 bytecode.
----------------------------------------------------------------------]]
--[[--------------------------------------------------------------------
-- Notes:
-- * LUA_NUMBER (double), byte order (little endian) and some other
-- header values hard-coded; see other notes below...
-- * One significant difference is that instructions are still in table
-- form (with OP/A/B/C/Bx fields) and luaP:Instruction() is needed to
-- convert them into 4-char strings
-- * Deleted:
-- luaU:DumpVector: folded into DumpLines, DumpCode
-- * Added:
-- luaU:endianness() (from lundump.c)
-- luaU:make_setS: create a chunk writer that writes to a string
-- luaU:make_setF: create a chunk writer that writes to a file
-- (lua.h contains a typedef for a Chunkwriter pointer, and
-- a Lua-based implementation exists, writer() in lstrlib.c)
-- luaU:from_double(x): encode double value for writing
-- luaU:from_int(x): encode integer value for writing
-- (error checking is limited for these conversion functions)
-- (double conversion does not support denormals or NaNs)
-- luaU:ttype(o) (from lobject.h)
----------------------------------------------------------------------]]
module("bytecode", package.seeall)
format = { }
format.header = string.dump(function()end):sub(1, 12)
format.little_endian, format.int_size,
format.size_t_size, format.instr_size,
format.number_size, format.integral = format.header:byte(7, 12)
format.little_endian = format.little_endian~=0
format.integral = format.integral ~=0
assert(format.integral or format.number_size==8, "Number format not supported by dumper")
assert(format.little_endian, "Big endian architectures not supported by dumper")
--requires luaP
luaU = {}
-- constants used by dumper
luaU.LUA_TNIL = 0
luaU.LUA_TBOOLEAN = 1
luaU.LUA_TNUMBER = 3 -- (all in lua.h)
luaU.LUA_TSTRING = 4
luaU.LUA_TNONE = -1
-- definitions for headers of binary files
--luaU.LUA_SIGNATURE = "\27Lua" -- binary files start with "<esc>Lua"
--luaU.VERSION = 81 -- 0x50; last format change was in 5.0
--luaU.FORMAT_VERSION = 0 -- 0 is official version. yeah I know I'm a liar.
-- a multiple of PI for testing native format
-- multiplying by 1E7 gives non-trivial integer values
--luaU.TEST_NUMBER = 3.14159265358979323846E7
--[[--------------------------------------------------------------------
-- Additional functions to handle chunk writing
-- * to use make_setS and make_setF, see test_ldump.lua elsewhere
----------------------------------------------------------------------]]
------------------------------------------------------------------------
-- works like the lobject.h version except that TObject used in these
-- scripts only has a 'value' field, no 'tt' field (native types used)
------------------------------------------------------------------------
function luaU:ttype(o)
local tt = type(o.value)
if tt == "number" then return self.LUA_TNUMBER
elseif tt == "string" then return self.LUA_TSTRING
elseif tt == "nil" then return self.LUA_TNIL
elseif tt == "boolean" then return self.LUA_TBOOLEAN
else
return self.LUA_TNONE -- the rest should not appear
end
end
------------------------------------------------------------------------
-- create a chunk writer that writes to a string
-- * returns the writer function and a table containing the string
-- * to get the final result, look in buff.data
------------------------------------------------------------------------
function luaU:make_setS()
local buff = {}
buff.data = ""
local writer =
function(s, buff) -- chunk writer
if not s then return end
buff.data = buff.data..s
end
return writer, buff
end
------------------------------------------------------------------------
-- create a chunk writer that writes to a file
-- * returns the writer function and a table containing the file handle
-- * if a nil is passed, then writer should close the open file
------------------------------------------------------------------------
function luaU:make_setF(filename)
local buff = {}
buff.h = io.open(filename, "wb")
if not buff.h then return nil end
local writer =
function(s, buff) -- chunk writer
if not buff.h then return end
if not s then buff.h:close(); return end
buff.h:write(s)
end
return writer, buff
end
-----------------------------------------------------------------------
-- converts a IEEE754 double number to an 8-byte little-endian string
-- * luaU:from_double() and luaU:from_int() are from ChunkBake project
-- * supports +/- Infinity, but not denormals or NaNs
-----------------------------------------------------------------------
function luaU:from_double(x)
local function grab_byte(v)
return math.floor(v / 256),
string.char(math.mod(math.floor(v), 256))
end
local sign = 0
if x < 0 then sign = 1; x = -x end
local mantissa, exponent = math.frexp(x)
if x == 0 then -- zero
mantissa, exponent = 0, 0
elseif x == 1/0 then
mantissa, exponent = 0, 2047
else
mantissa = (mantissa * 2 - 1) * math.ldexp(0.5, 53)
exponent = exponent + 1022
end
local v, byte = "" -- convert to bytes
x = mantissa
for i = 1,6 do
x, byte = grab_byte(x); v = v..byte -- 47:0
end
x, byte = grab_byte(exponent * 16 + x); v = v..byte -- 55:48
x, byte = grab_byte(sign * 128 + x); v = v..byte -- 63:56
return v
end
-----------------------------------------------------------------------
-- converts a number to a little-endian 32-bit integer string
-- * input value assumed to not overflow, can be signed/unsigned
-----------------------------------------------------------------------
function luaU:from_int(x, size)
local v = ""
x = math.floor(x)
if x >= 0 then
for i = 1, size do
v = v..string.char(math.mod(x, 256)); x = math.floor(x / 256)
end
else -- x < 0
x = -x
local carry = 1
for i = 1, size do
local c = 255 - math.mod(x, 256) + carry
if c == 256 then c = 0; carry = 1 else carry = 0 end
v = v..string.char(c); x = math.floor(x / 256)
end
end
return v
end
--[[--------------------------------------------------------------------
-- Functions to make a binary chunk
-- * many functions have the size parameter removed, since output is
-- in the form of a string and some sizes are implicit or hard-coded
-- * luaU:DumpVector has been deleted (used in DumpCode & DumpLines)
----------------------------------------------------------------------]]
------------------------------------------------------------------------
-- dump a block of literal bytes
------------------------------------------------------------------------
function luaU:DumpLiteral(s, D) self:DumpBlock(s, D) end
--[[--------------------------------------------------------------------
-- struct DumpState:
-- L -- lua_State (not used in this script)
-- write -- lua_Chunkwriter (chunk writer function)
-- data -- void* (chunk writer context or data already written)
----------------------------------------------------------------------]]
------------------------------------------------------------------------
-- dumps a block of bytes
-- * lua_unlock(D.L), lua_lock(D.L) deleted
------------------------------------------------------------------------
function luaU:DumpBlock(b, D) D.write(b, D.data) end
------------------------------------------------------------------------
-- dumps a single byte
------------------------------------------------------------------------
function luaU:DumpByte(y, D)
self:DumpBlock(string.char(y), D)
end
------------------------------------------------------------------------
-- dumps a 32-bit signed integer (for int)
------------------------------------------------------------------------
function luaU:DumpInt(x, D)
self:DumpBlock(self:from_int(x, format.int_size), D)
end
------------------------------------------------------------------------
-- dumps a 32-bit unsigned integer (for size_t)
------------------------------------------------------------------------
function luaU:DumpSize(x, D)
self:DumpBlock(self:from_int(x, format.size_t_size), D)
end
------------------------------------------------------------------------
-- dumps a LUA_NUMBER (hard-coded as a double)
------------------------------------------------------------------------
function luaU:DumpNumber(x, D)
if format.integral then
self:DumpBlock(self:from_int(x, format.number_size), D)
else
self:DumpBlock(self:from_double(x), D)
end
end
------------------------------------------------------------------------
-- dumps a Lua string
------------------------------------------------------------------------
function luaU:DumpString(s, D)
if s == nil then
self:DumpSize(0, D)
else
s = s.."\0" -- include trailing '\0'
self:DumpSize(string.len(s), D)
self:DumpBlock(s, D)
end
end
------------------------------------------------------------------------
-- dumps instruction block from function prototype
------------------------------------------------------------------------
function luaU:DumpCode(f, D)
local n = f.sizecode
self:DumpInt(n, D)
--was DumpVector
for i = 0, n - 1 do
self:DumpBlock(luaP:Instruction(f.code[i]), D)
end
end
------------------------------------------------------------------------
-- dumps local variable names from function prototype
------------------------------------------------------------------------
function luaU:DumpLocals(f, D)
local n = f.sizelocvars
self:DumpInt(n, D)
for i = 0, n - 1 do
-- Dirty temporary fix:
-- `Stat{ } keeps properly count of the number of local vars,
-- but fails to keep score of their debug info (names).
-- It therefore might happen that #f.localvars < f.sizelocvars, or
-- that a variable's startpc and endpc fields are left unset.
-- FIXME: This might not be needed anymore, check the bug report
-- by J. Belmonte.
local var = f.locvars[i]
if not var then break end
-- printf("[DUMPLOCALS] dumping local var #%i = %s", i, table.tostring(var))
self:DumpString(var.varname, D)
self:DumpInt(var.startpc or 0, D)
self:DumpInt(var.endpc or 0, D)
end
end
------------------------------------------------------------------------
-- dumps line information from function prototype
------------------------------------------------------------------------
function luaU:DumpLines(f, D)
local n = f.sizelineinfo
self:DumpInt(n, D)
--was DumpVector
for i = 0, n - 1 do
self:DumpInt(f.lineinfo[i], D) -- was DumpBlock
--print(i, f.lineinfo[i])
end
end
------------------------------------------------------------------------
-- dump upvalue names from function prototype
------------------------------------------------------------------------
function luaU:DumpUpvalues(f, D)
local n = f.sizeupvalues
self:DumpInt(n, D)
for i = 0, n - 1 do
self:DumpString(f.upvalues[i], D)
end
end
------------------------------------------------------------------------
-- dump constant pool from function prototype
-- * nvalue(o) and tsvalue(o) macros removed
------------------------------------------------------------------------
function luaU:DumpConstants(f, D)
local n = f.sizek
self:DumpInt(n, D)
for i = 0, n - 1 do
local o = f.k[i] -- TObject
local tt = self:ttype(o)
assert (tt >= 0)
self:DumpByte(tt, D)
if tt == self.LUA_TNUMBER then
self:DumpNumber(o.value, D)
elseif tt == self.LUA_TSTRING then
self:DumpString(o.value, D)
elseif tt == self.LUA_TBOOLEAN then
self:DumpByte (o.value and 1 or 0, D)
elseif tt == self.LUA_TNIL then
else
assert(false) -- cannot happen
end
end
end
function luaU:DumpProtos (f, D)
local n = f.sizep
assert (n)
self:DumpInt(n, D)
for i = 0, n - 1 do
self:DumpFunction(f.p[i], f.source, D)
end
end
function luaU:DumpDebug(f, D)
self:DumpLines(f, D)
self:DumpLocals(f, D)
self:DumpUpvalues(f, D)
end
------------------------------------------------------------------------
-- dump child function prototypes from function prototype
--FF completely reworked for 5.1 format
------------------------------------------------------------------------
function luaU:DumpFunction(f, p, D)
-- print "Dumping function:"
-- table.print(f, 60)
local source = f.source
if source == p then source = nil end
self:DumpString(source, D)
self:DumpInt(f.lineDefined, D)
self:DumpInt(f.lastLineDefined or 42, D)
self:DumpByte(f.nups, D)
self:DumpByte(f.numparams, D)
self:DumpByte(f.is_vararg, D)
self:DumpByte(f.maxstacksize, D)
self:DumpCode(f, D)
self:DumpConstants(f, D)
self:DumpProtos( f, D)
self:DumpDebug(f, D)
end
------------------------------------------------------------------------
-- dump Lua header section (some sizes hard-coded)
--FF: updated for version 5.1
------------------------------------------------------------------------
function luaU:DumpHeader(D)
self:DumpLiteral(format.header, D)
end
------------------------------------------------------------------------
-- dump function as precompiled chunk
-- * w, data are created from make_setS, make_setF
--FF: suppressed extraneous [L] param
------------------------------------------------------------------------
function luaU:dump (Main, w, data)
local D = {} -- DumpState
D.write = w
D.data = data
self:DumpHeader(D)
self:DumpFunction(Main, nil, D)
-- added: for a chunk writer writing to a file, this final call with
-- nil data is to indicate to the writer to close the file
D.write(nil, D.data)
end
------------------------------------------------------------------------
-- find byte order (from lundump.c)
-- * hard-coded to little-endian
------------------------------------------------------------------------
function luaU:endianness()
return 1
end
-- FIXME: ugly concat-base generation in [make_setS], bufferize properly!
function dump_string (proto)
local writer, buff = luaU:make_setS()
luaU:dump (proto, writer, buff)
return buff.data
end
-- FIXME: [make_setS] sucks, perform synchronous file writing
-- Now unused
function dump_file (proto, filename)
local writer, buff = luaU:make_setS()
luaU:dump (proto, writer, buff)
local file = io.open (filename, "wb")
file:write (buff.data)
io.close(file)
if UNIX_SHARPBANG then os.execute ("chmod a+x "..filename) end
end

510
lualibs/metalua/lexer.lua Normal file
View File

@@ -0,0 +1,510 @@
----------------------------------------------------------------------
-- Metalua: $Id: mll.lua,v 1.3 2006/11/15 09:07:50 fab13n Exp $
--
-- Summary: generic Lua-style lexer definition. You need this plus
-- some keyword additions to create the complete Lua lexer,
-- as is done in mlp_lexer.lua.
--
-- TODO:
--
-- * Make it easy to define new flavors of strings. Replacing the
-- lexer.patterns.long_string regexp by an extensible list, with
-- customizable token tag, would probably be enough. Maybe add:
-- + an index of capture for the regexp, that would specify
-- which capture holds the content of the string-like token
-- + a token tag
-- + or a string->string transformer function.
--
-- * There are some _G.table to prevent a namespace clash which has
-- now disappered. remove them.
----------------------------------------------------------------------
--
-- Copyright (c) 2006, Fabien Fleutot <metalua@gmail.com>.
--
-- This software is released under the MIT Licence, see licence.txt
-- for details.
--
----------------------------------------------------------------------
module ("lexer", package.seeall)
require 'metalua.runtime'
lexer = { alpha={ }, sym={ } }
lexer.__index=lexer
local debugf = function() end
--local debugf=printf
----------------------------------------------------------------------
-- Patterns used by [lexer:extract] to decompose the raw string into
-- correctly tagged tokens.
----------------------------------------------------------------------
lexer.patterns = {
spaces = "^[ \r\n\t]*()",
short_comment = "^%-%-([^\n]*)()\n",
final_short_comment = "^%-%-([^\n]*)()$",
long_comment = "^%-%-%[(=*)%[\n?(.-)%]%1%]()",
long_string = "^%[(=*)%[\n?(.-)%]%1%]()",
number_mantissa = { "^%d+%.?%d*()", "^%d*%.%d+()" },
number_exponant = "^[eE][%+%-]?%d+()",
number_hex = "^0[xX]%x+()",
word = "^([%a_][%w_]*)()"
}
----------------------------------------------------------------------
-- unescape a whole string, applying [unesc_digits] and
-- [unesc_letter] as many times as required.
----------------------------------------------------------------------
local function unescape_string (s)
-- Turn the digits of an escape sequence into the corresponding
-- character, e.g. [unesc_digits("123") == string.char(123)].
local function unesc_digits (backslashes, digits)
if #backslashes%2==0 then
-- Even number of backslashes, they escape each other, not the digits.
-- Return them so that unesc_letter() can treaat them
return backslashes..digits
else
-- Remove the odd backslash, which escapes the number sequence.
-- The rest will be returned and parsed by unesc_letter()
backslashes = backslashes :sub (1,-2)
end
local k, j, i = digits:reverse():byte(1, 3)
local z = _G.string.byte "0"
local code = (k or z) + 10*(j or z) + 100*(i or z) - 111*z
if code > 255 then
error ("Illegal escape sequence '\\"..digits..
"' in string: ASCII codes must be in [0..255]")
end
return backslashes .. string.char (code)
end
-- Take a letter [x], and returns the character represented by the
-- sequence ['\\'..x], e.g. [unesc_letter "n" == "\n"].
local function unesc_letter(x)
local t = {
a = "\a", b = "\b", f = "\f",
n = "\n", r = "\r", t = "\t", v = "\v",
["\\"] = "\\", ["'"] = "'", ['"'] = '"', ["\n"] = "\n" }
return t[x] or error([[Unknown escape sequence '\]]..x..[[']])
end
return s
:gsub ("(\\+)([0-9][0-9]?[0-9]?)", unesc_digits)
:gsub ("\\(%D)",unesc_letter)
end
lexer.extractors = {
"skip_whitespaces_and_comments",
"extract_short_string", "extract_word", "extract_number",
"extract_long_string", "extract_symbol" }
lexer.token_metatable = {
-- __tostring = function(a)
-- return string.format ("`%s{'%s'}",a.tag, a[1])
-- end
}
lexer.lineinfo_metatable = { }
----------------------------------------------------------------------
-- Really extract next token fron the raw string
-- (and update the index).
-- loc: offset of the position just after spaces and comments
-- previous_i: offset in src before extraction began
----------------------------------------------------------------------
function lexer:extract ()
local previous_i = self.i
local loc = self.i
local eof, token
-- Put line info, comments and metatable around the tag and content
-- provided by extractors, thus returning a complete lexer token.
-- first_line: line # at the beginning of token
-- first_column_offset: char # of the last '\n' before beginning of token
-- i: scans from beginning of prefix spaces/comments to end of token.
local function build_token (tag, content)
assert (tag and content)
local i, first_line, first_column_offset, previous_line_length =
previous_i, self.line, self.column_offset, nil
-- update self.line and first_line. i := indexes of '\n' chars
while true do
i = self.src :find ("\n", i+1, true)
if not i or i>self.i then break end -- no more '\n' until end of token
previous_line_length = i - self.column_offset
if loc and i <= loc then -- '\n' before beginning of token
first_column_offset = i
first_line = first_line+1
end
self.line = self.line+1
self.column_offset = i
end
-- lineinfo entries: [1]=line, [2]=column, [3]=char, [4]=filename
local fli = { first_line, loc-first_column_offset, loc, self.src_name }
local lli = { self.line, self.i-self.column_offset-1, self.i-1, self.src_name }
--Pluto barfes when the metatable is set:(
setmetatable(fli, lexer.lineinfo_metatable)
setmetatable(lli, lexer.lineinfo_metatable)
local a = { tag = tag, lineinfo = { first=fli, last=lli }, content }
if lli[2]==-1 then lli[1], lli[2] = lli[1]-1, previous_line_length-1 end
if #self.attached_comments > 0 then
a.lineinfo.comments = self.attached_comments
fli.comments = self.attached_comments
if self.lineinfo_last then
self.lineinfo_last.comments = self.attached_comments
end
end
self.attached_comments = { }
return setmetatable (a, self.token_metatable)
end --</function build_token>
for ext_idx, extractor in ipairs(self.extractors) do
-- printf("method = %s", method)
local tag, content = self [extractor] (self)
-- [loc] is placed just after the leading whitespaces and comments;
-- for this to work, the whitespace extractor *must be* at index 1.
if ext_idx==1 then loc = self.i end
if tag then
--printf("`%s{ %q }\t%i", tag, content, loc);
return build_token (tag, content)
end
end
error "None of the lexer extractors returned anything!"
end
----------------------------------------------------------------------
-- skip whites and comments
-- FIXME: doesn't take into account:
-- - unterminated long comments
-- - short comments at last line without a final \n
----------------------------------------------------------------------
function lexer:skip_whitespaces_and_comments()
local table_insert = _G.table.insert
repeat -- loop as long as a space or comment chunk is found
local _, j
local again = false
local last_comment_content = nil
-- skip spaces
self.i = self.src:match (self.patterns.spaces, self.i)
-- skip a long comment if any
_, last_comment_content, j =
self.src :match (self.patterns.long_comment, self.i)
if j then
table_insert(self.attached_comments,
{last_comment_content, self.i, j, "long"})
self.i=j; again=true
end
-- skip a short comment if any
last_comment_content, j = self.src:match (self.patterns.short_comment, self.i)
if j then
table_insert(self.attached_comments,
{last_comment_content, self.i, j, "short"})
self.i=j; again=true
end
if self.i>#self.src then return "Eof", "eof" end
until not again
if self.src:match (self.patterns.final_short_comment, self.i) then
return "Eof", "eof" end
--assert (not self.src:match(self.patterns.short_comment, self.i))
--assert (not self.src:match(self.patterns.long_comment, self.i))
-- --assert (not self.src:match(self.patterns.spaces, self.i))
return
end
----------------------------------------------------------------------
-- extract a '...' or "..." short string
----------------------------------------------------------------------
function lexer:extract_short_string()
-- [k] is the first unread char, [self.i] points to [k] in [self.src]
local j, k = self.i, self.src :sub (self.i,self.i)
if k~="'" and k~='"' then return end
local i = self.i + 1
local j = i
while true do
-- k = opening char: either simple-quote or double-quote
-- i = index of beginning-of-string
-- x = next "interesting" character
-- j = position after interesting char
-- y = char just after x
local x, y
x, j, y = self.src :match ("([\\\r\n"..k.."])()(.?)", j)
if x == '\\' then j=j+1 -- don't parse escaped char
elseif x == k then break -- unescaped end of string
else -- eof or '\r' or '\n' reached before end of string
assert (not x or x=="\r" or x=="\n")
error "Unterminated string"
end
end
self.i = j
return "String", unescape_string (self.src:sub (i,j-2))
end
----------------------------------------------------------------------
--
----------------------------------------------------------------------
function lexer:extract_word()
-- Id / keyword
local word, j = self.src:match (self.patterns.word, self.i)
if word then
self.i = j
if self.alpha [word] then return "Keyword", word
else return "Id", word end
end
end
----------------------------------------------------------------------
--
----------------------------------------------------------------------
function lexer:extract_number()
-- Number
local j = self.src:match(self.patterns.number_hex, self.i)
if not j then
j = self.src:match (self.patterns.number_mantissa[1], self.i) or
self.src:match (self.patterns.number_mantissa[2], self.i)
if j then
j = self.src:match (self.patterns.number_exponant, j) or j;
end
end
if not j then return end
-- Number found, interpret with tonumber() and return it
local n = tonumber (self.src:sub (self.i, j-1))
self.i = j
return "Number", n
end
----------------------------------------------------------------------
--
----------------------------------------------------------------------
function lexer:extract_long_string()
-- Long string
local _, content, j = self.src:match (self.patterns.long_string, self.i)
if j then self.i = j; return "String", content end
end
----------------------------------------------------------------------
--
----------------------------------------------------------------------
function lexer:extract_symbol()
-- compound symbol
local k = self.src:sub (self.i,self.i)
local symk = self.sym [k]
if not symk then
self.i = self.i + 1
return "Keyword", k
end
for _, sym in pairs (symk) do
if sym == self.src:sub (self.i, self.i + #sym - 1) then
self.i = self.i + #sym;
return "Keyword", sym
end
end
-- single char symbol
self.i = self.i+1
return "Keyword", k
end
----------------------------------------------------------------------
-- Add a keyword to the list of keywords recognized by the lexer.
----------------------------------------------------------------------
function lexer:add (w, ...)
assert(not ..., "lexer:add() takes only one arg, although possibly a table")
if type (w) == "table" then
for _, x in ipairs (w) do self:add (x) end
else
if w:match (self.patterns.word .. "$") then self.alpha [w] = true
elseif w:match "^%p%p+$" then
local k = w:sub(1,1)
local list = self.sym [k]
if not list then list = { }; self.sym [k] = list end
_G.table.insert (list, w)
elseif w:match "^%p$" then return
else error "Invalid keyword" end
end
end
----------------------------------------------------------------------
-- Return the [n]th next token, without consumming it.
-- [n] defaults to 1. If it goes pass the end of the stream, an EOF
-- token is returned.
----------------------------------------------------------------------
function lexer:peek (n)
if not n then n=1 end
if n > #self.peeked then
for i = #self.peeked+1, n do
self.peeked [i] = self:extract()
end
end
return self.peeked [n]
end
----------------------------------------------------------------------
-- Return the [n]th next token, removing it as well as the 0..n-1
-- previous tokens. [n] defaults to 1. If it goes pass the end of the
-- stream, an EOF token is returned.
----------------------------------------------------------------------
function lexer:next (n)
n = n or 1
self:peek (n)
local a
for i=1,n do
a = _G.table.remove (self.peeked, 1)
if a then
--debugf ("lexer:next() ==> %s %s",
-- table.tostring(a), tostring(a))
end
self.lastline = a.lineinfo.last[1]
end
self.lineinfo_last = a.lineinfo.last
return a or eof_token
end
----------------------------------------------------------------------
-- Returns an object which saves the stream's current state.
----------------------------------------------------------------------
-- FIXME there are more fields than that to save
function lexer:save () return { self.i; _G.table.cat(self.peeked) } end
----------------------------------------------------------------------
-- Restore the stream's state, as saved by method [save].
----------------------------------------------------------------------
-- FIXME there are more fields than that to restore
function lexer:restore (s) self.i=s[1]; self.peeked=s[2] end
----------------------------------------------------------------------
-- Resynchronize: cancel any token in self.peeked, by emptying the
-- list and resetting the indexes
----------------------------------------------------------------------
function lexer:sync()
local p1 = self.peeked[1]
if p1 then
li = p1.lineinfo.first
self.line, self.i = li[1], li[3]
self.column_offset = self.i - li[2]
self.peeked = { }
self.attached_comments = p1.lineinfo.first.comments or { }
end
end
----------------------------------------------------------------------
-- Take the source and offset of an old lexer.
----------------------------------------------------------------------
function lexer:takeover(old)
self:sync()
self.line, self.column_offset, self.i, self.src, self.attached_comments =
old.line, old.column_offset, old.i, old.src, old.attached_comments
return self
end
-- function lexer:lineinfo()
-- if self.peeked[1] then return self.peeked[1].lineinfo.first
-- else return { self.line, self.i-self.column_offset, self.i } end
-- end
----------------------------------------------------------------------
-- Return the current position in the sources. This position is between
-- two tokens, and can be within a space / comment area, and therefore
-- have a non-null width. :lineinfo_left() returns the beginning of the
-- separation area, :lineinfo_right() returns the end of that area.
--
-- ____ last consummed token ____ first unconsummed token
-- / /
-- XXXXX <spaces and comments> YYYYY
-- \____ \____
-- :lineinfo_left() :lineinfo_right()
----------------------------------------------------------------------
function lexer:lineinfo_right()
return self:peek(1).lineinfo.first
end
function lexer:lineinfo_left()
return self.lineinfo_last
end
----------------------------------------------------------------------
-- Create a new lexstream.
----------------------------------------------------------------------
function lexer:newstream (src_or_stream, name)
name = name or "?"
if type(src_or_stream)=='table' then -- it's a stream
return setmetatable ({ }, self) :takeover (src_or_stream)
elseif type(src_or_stream)=='string' then -- it's a source string
local src = src_or_stream
local stream = {
src_name = name; -- Name of the file
src = src; -- The source, as a single string
peeked = { }; -- Already peeked, but not discarded yet, tokens
i = 1; -- Character offset in src
line = 1; -- Current line number
column_offset = 0; -- distance from beginning of file to last '\n'
attached_comments = { },-- comments accumulator
lineinfo_last = { 1, 1, 1, name }
}
setmetatable (stream, self)
-- skip initial sharp-bang for unix scripts
-- FIXME: redundant with mlp.chunk()
if src and src :match "^#" then stream.i = src :find "\n" + 1 end
return stream
else
assert(false, ":newstream() takes a source string or a stream, not a "..
type(src_or_stream))
end
end
----------------------------------------------------------------------
-- if there's no ... args, return the token a (whose truth value is
-- true) if it's a `Keyword{ }, or nil. If there are ... args, they
-- have to be strings. if the token a is a keyword, and it's content
-- is one of the ... args, then returns it (it's truth value is
-- true). If no a keyword or not in ..., return nil.
----------------------------------------------------------------------
function lexer:is_keyword (a, ...)
if not a or a.tag ~= "Keyword" then return false end
local words = {...}
if #words == 0 then return a[1] end
for _, w in ipairs (words) do
if w == a[1] then return w end
end
return false
end
----------------------------------------------------------------------
-- Cause an error if the next token isn't a keyword whose content
-- is listed among ... args (which have to be strings).
----------------------------------------------------------------------
function lexer:check (...)
local words = {...}
local a = self:next()
local function err ()
error ("Got " .. tostring (a) ..
", expected one of these keywords : '" ..
_G.table.concat (words,"', '") .. "'") end
if not a or a.tag ~= "Keyword" then err () end
if #words == 0 then return a[1] end
for _, w in ipairs (words) do
if w == a[1] then return w end
end
err ()
end
----------------------------------------------------------------------
--
----------------------------------------------------------------------
function lexer:clone()
local clone = {
alpha = table.deep_copy(self.alpha),
sym = table.deep_copy(self.sym) }
setmetatable(clone, self)
clone.__index = clone
return clone
end

View File

@@ -0,0 +1,440 @@
----------------------------------------------------------------------
--
-- WARNING! You're entering a hackish area, proceed at your own risks!
--
-- This code results from the borrowing, then ruthless abuse, of
-- Yueliang's implementation of Lua 5.0 compiler. I claim
-- responsibility for all of the ugly, dirty stuff that you might spot
-- in it.
--
-- Eventually, this code will be rewritten, either in Lua or more
-- probably in C. Meanwhile, if you're interested into digging
-- metalua's sources, this is not the best part to invest your time
-- on.
--
-- End of warning.
--
----------------------------------------------------------------------
--[[--------------------------------------------------------------------
$Id$
lopcodes.lua
Lua 5 virtual machine opcodes in Lua
This file is part of Yueliang.
Copyright (c) 2005 Kein-Hong Man <khman@users.sf.net>
The COPYRIGHT file describes the conditions
under which this software may be distributed.
See the ChangeLog for more information.
------------------------------------------------------------------------
[FF] Slightly modified, mainly to produce Lua 5.1 bytecode.
----------------------------------------------------------------------]]
--[[--------------------------------------------------------------------
-- Notes:
-- * an Instruction is a table with OP, A, B, C, Bx elements; this
-- should allow instruction handling to work with doubles and ints
-- * Added:
-- luaP:Instruction(i): convert field elements to a 4-char string
-- luaP:DecodeInst(x): convert 4-char string into field elements
-- * WARNING luaP:Instruction outputs instructions encoded in little-
-- endian form and field size and positions are hard-coded
----------------------------------------------------------------------]]
module("bytecode", package.seeall)
local function debugf() end
luaP = { }
--[[
===========================================================================
We assume that instructions are unsigned numbers.
All instructions have an opcode in the first 6 bits.
Instructions can have the following fields:
'A' : 8 bits
'B' : 9 bits
'C' : 9 bits
'Bx' : 18 bits ('B' and 'C' together)
'sBx' : signed Bx
A signed argument is represented in excess K; that is, the number
value is the unsigned value minus K. K is exactly the maximum value
for that argument (so that -max is represented by 0, and +max is
represented by 2*max), which is half the maximum for the corresponding
unsigned argument.
===========================================================================
--]]
luaP.OpMode = {"iABC", "iABx", "iAsBx"} -- basic instruction format
------------------------------------------------------------------------
-- size and position of opcode arguments.
-- * WARNING size and position is hard-coded elsewhere in this script
------------------------------------------------------------------------
luaP.SIZE_C = 9
luaP.SIZE_B = 9
luaP.SIZE_Bx = luaP.SIZE_C + luaP.SIZE_B
luaP.SIZE_A = 8
luaP.SIZE_OP = 6
luaP.POS_C = luaP.SIZE_OP
luaP.POS_B = luaP.POS_C + luaP.SIZE_C
luaP.POS_Bx = luaP.POS_C
luaP.POS_A = luaP.POS_B + luaP.SIZE_B
--FF from 5.1
luaP.BITRK = 2^(luaP.SIZE_B - 1)
function luaP:ISK(x) return x >= self.BITRK end
luaP.MAXINDEXRK = luaP.BITRK - 1
function luaP:RKASK(x)
if x < self.BITRK then return x+self.BITRK else return x end
end
------------------------------------------------------------------------
-- limits for opcode arguments.
-- we use (signed) int to manipulate most arguments,
-- so they must fit in BITS_INT-1 bits (-1 for sign)
------------------------------------------------------------------------
-- removed "#if SIZE_Bx < BITS_INT-1" test, assume this script is
-- running on a Lua VM with double or int as LUA_NUMBER
luaP.MAXARG_Bx = math.ldexp(1, luaP.SIZE_Bx) - 1
luaP.MAXARG_sBx = math.floor(luaP.MAXARG_Bx / 2) -- 'sBx' is signed
luaP.MAXARG_A = math.ldexp(1, luaP.SIZE_A) - 1
luaP.MAXARG_B = math.ldexp(1, luaP.SIZE_B) - 1
luaP.MAXARG_C = math.ldexp(1, luaP.SIZE_C) - 1
-- creates a mask with 'n' 1 bits at position 'p'
-- MASK1(n,p) deleted
-- creates a mask with 'n' 0 bits at position 'p'
-- MASK0(n,p) deleted
--[[--------------------------------------------------------------------
Visual representation for reference:
31 | | | 0 bit position
+-----+-----+-----+----------+
| B | C | A | Opcode | iABC format
+-----+-----+-----+----------+
- 9 - 9 - 8 - 6 - field sizes
+-----+-----+-----+----------+
| [s]Bx | A | Opcode | iABx | iAsBx format
+-----+-----+-----+----------+
----------------------------------------------------------------------]]
------------------------------------------------------------------------
-- the following macros help to manipulate instructions
-- * changed to a table object representation, very clean compared to
-- the [nightmare] alternatives of using a number or a string
------------------------------------------------------------------------
-- these accept or return opcodes in the form of string names
function luaP:GET_OPCODE(i) return self.ROpCode[i.OP] end
function luaP:SET_OPCODE(i, o) i.OP = self.OpCode[o] end
function luaP:GETARG_A(i) return i.A end
function luaP:SETARG_A(i, u) i.A = u end
function luaP:GETARG_B(i) return i.B end
function luaP:SETARG_B(i, b) i.B = b end
function luaP:GETARG_C(i) return i.C end
function luaP:SETARG_C(i, b) i.C = b end
function luaP:GETARG_Bx(i) return i.Bx end
function luaP:SETARG_Bx(i, b) i.Bx = b end
function luaP:GETARG_sBx(i) return i.Bx - self.MAXARG_sBx end
function luaP:SETARG_sBx(i, b) i.Bx = b + self.MAXARG_sBx end
function luaP:CREATE_ABC(o,a,b,c)
return {OP = self.OpCode[o], A = a, B = b, C = c}
end
function luaP:CREATE_ABx(o,a,bc)
return {OP = self.OpCode[o], A = a, Bx = bc}
end
------------------------------------------------------------------------
-- Bit shuffling stuffs
------------------------------------------------------------------------
if false and pcall (require, 'bit') then
------------------------------------------------------------------------
-- Return a 4-char string little-endian encoded form of an instruction
------------------------------------------------------------------------
function luaP:Instruction(i)
--FIXME
end
else
------------------------------------------------------------------------
-- Version without bit manipulation library.
------------------------------------------------------------------------
local p2 = {1,2,4,8,16,32,64,128,256, 512, 1024, 2048, 4096}
-- keeps [n] bits from [x]
local function keep (x, n) return x % p2[n+1] end
-- shifts bits of [x] [n] places to the right
local function srb (x,n) return math.floor (x / p2[n+1]) end
-- shifts bits of [x] [n] places to the left
local function slb (x,n) return x * p2[n+1] end
------------------------------------------------------------------------
-- Return a 4-char string little-endian encoded form of an instruction
------------------------------------------------------------------------
function luaP:Instruction(i)
-- printf("Instr->string: %s %s", self.opnames[i.OP], table.tostring(i))
local c0, c1, c2, c3
-- change to OP/A/B/C format if needed
if i.Bx then i.C = keep (i.Bx, 9); i.B = srb (i.Bx, 9) end
-- c0 = 6B from opcode + 2LSB from A (flushed to MSB)
c0 = i.OP + slb (keep (i.A, 2), 6)
-- c1 = 6MSB from A + 2LSB from C (flushed to MSB)
c1 = srb (i.A, 2) + slb (keep (i.C, 2), 6)
-- c2 = 7MSB from C + 1LSB from B (flushed to MSB)
c2 = srb (i.C, 2) + slb (keep (i.B, 1), 7)
-- c3 = 8MSB from B
c3 = srb (i.B, 1)
--printf ("Instruction: %s %s", self.opnames[i.OP], tostringv (i))
--printf ("Bin encoding: %x %x %x %x", c0, c1, c2, c3)
return string.char(c0, c1, c2, c3)
end
end
------------------------------------------------------------------------
-- decodes a 4-char little-endian string into an instruction struct
------------------------------------------------------------------------
function luaP:DecodeInst(x)
error "Not implemented"
end
------------------------------------------------------------------------
-- invalid register that fits in 8 bits
------------------------------------------------------------------------
luaP.NO_REG = luaP.MAXARG_A
------------------------------------------------------------------------
-- R(x) - register
-- Kst(x) - constant (in constant table)
-- RK(x) == if x < MAXSTACK then R(x) else Kst(x-MAXSTACK)
------------------------------------------------------------------------
------------------------------------------------------------------------
-- grep "ORDER OP" if you change these enums
------------------------------------------------------------------------
--[[--------------------------------------------------------------------
Lua virtual machine opcodes (enum OpCode):
------------------------------------------------------------------------
name args description
------------------------------------------------------------------------
OP_MOVE A B R(A) := R(B)
OP_LOADK A Bx R(A) := Kst(Bx)
OP_LOADBOOL A B C R(A) := (Bool)B; if (C) PC++
OP_LOADNIL A B R(A) := ... := R(B) := nil
OP_GETUPVAL A B R(A) := UpValue[B]
OP_GETGLOBAL A Bx R(A) := Gbl[Kst(Bx)]
OP_GETTABLE A B C R(A) := R(B)[RK(C)]
OP_SETGLOBAL A Bx Gbl[Kst(Bx)] := R(A)
OP_SETUPVAL A B UpValue[B] := R(A)
OP_SETTABLE A B C R(A)[RK(B)] := RK(C)
OP_NEWTABLE A B C R(A) := {} (size = B,C)
OP_SELF A B C R(A+1) := R(B); R(A) := R(B)[RK(C)]
OP_ADD A B C R(A) := RK(B) + RK(C)
OP_SUB A B C R(A) := RK(B) - RK(C)
OP_MUL A B C R(A) := RK(B) * RK(C)
OP_DIV A B C R(A) := RK(B) / RK(C)
OP_POW A B C R(A) := RK(B) ^ RK(C)
OP_UNM A B R(A) := -R(B)
OP_NOT A B R(A) := not R(B)
OP_CONCAT A B C R(A) := R(B).. ... ..R(C)
OP_JMP sBx PC += sBx
OP_EQ A B C if ((RK(B) == RK(C)) ~= A) then pc++
OP_LT A B C if ((RK(B) < RK(C)) ~= A) then pc++
OP_LE A B C if ((RK(B) <= RK(C)) ~= A) then pc++
OP_TEST A B C if (R(B) <=> C) then R(A) := R(B) else pc++
OP_CALL A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1))
OP_TAILCALL A B C return R(A)(R(A+1), ... ,R(A+B-1))
OP_RETURN A B return R(A), ... ,R(A+B-2) (see note)
OP_FORLOOP A sBx R(A)+=R(A+2); if R(A) <?= R(A+1) then PC+= sBx
OP_TFORLOOP A C R(A+2), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2));
if R(A+2) ~= nil then pc++
OP_TFORPREP A sBx if type(R(A)) == table then R(A+1):=R(A), R(A):=next;
PC += sBx
OP_SETLIST A Bx R(A)[Bx-Bx%FPF+i] := R(A+i), 1 <= i <= Bx%FPF+1
OP_SETLISTO A Bx (see note)
OP_CLOSE A close all variables in the stack up to (>=) R(A)
OP_CLOSURE A Bx R(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n))
----------------------------------------------------------------------]]
luaP.opnames = {} -- opcode names
luaP.OpCode = {} -- lookup name -> number
luaP.ROpCode = {} -- lookup number -> name
local i = 0
for v in string.gfind([[
MOVE -- 0
LOADK
LOADBOOL
LOADNIL
GETUPVAL
GETGLOBAL -- 5
GETTABLE
SETGLOBAL
SETUPVAL
SETTABLE
NEWTABLE -- 10
SELF
ADD
SUB
MUL
DIV -- 15
MOD
POW
UNM
NOT
LEN -- 20
CONCAT
JMP
EQ
LT
LE -- 25
TEST
TESTSET
CALL
TAILCALL
RETURN -- 30
FORLOOP
FORPREP
TFORLOOP
SETLIST
CLOSE -- 35
CLOSURE
VARARG
]], "[%a]+") do
local n = "OP_"..v
luaP.opnames[i] = v
luaP.OpCode[n] = i
luaP.ROpCode[i] = n
i = i + 1
end
luaP.NUM_OPCODES = i
--[[
===========================================================================
Notes:
(1) In OP_CALL, if (B == 0) then B = top. C is the number of returns - 1,
and can be 0: OP_CALL then sets 'top' to last_result+1, so
next open instruction (OP_CALL, OP_RETURN, OP_SETLIST) may use 'top'.
(2) In OP_RETURN, if (B == 0) then return up to 'top'
(3) For comparisons, B specifies what conditions the test should accept.
(4) All 'skips' (pc++) assume that next instruction is a jump
(5) OP_SETLISTO is used when the last item in a table constructor is a
function, so the number of elements set is up to top of stack
===========================================================================
--]]
------------------------------------------------------------------------
-- masks for instruction properties
------------------------------------------------------------------------
-- was enum OpModeMask:
luaP.OpModeBreg = 2 -- B is a register
luaP.OpModeBrk = 3 -- B is a register/constant
luaP.OpModeCrk = 4 -- C is a register/constant
luaP.OpModesetA = 5 -- instruction set register A
luaP.OpModeK = 6 -- Bx is a constant
luaP.OpModeT = 1 -- operator is a test
------------------------------------------------------------------------
-- get opcode mode, e.g. "iABC"
------------------------------------------------------------------------
function luaP:getOpMode(m)
--printv(m)
--printv(self.OpCode[m])
--printv(self.opmodes [self.OpCode[m]+1])
return self.OpMode[tonumber(string.sub(self.opmodes[self.OpCode[m] + 1], 7, 7))]
end
------------------------------------------------------------------------
-- test an instruction property flag
-- * b is a string, e.g. "OpModeBreg"
------------------------------------------------------------------------
function luaP:testOpMode(m, b)
return (string.sub(self.opmodes[self.OpCode[m] + 1], self[b], self[b]) == "1")
end
-- number of list items to accumulate before a SETLIST instruction
-- (must be a power of 2)
-- * used in lparser, lvm, ldebug, ltests
luaP.LFIELDS_PER_FLUSH = 50 --FF updated to match 5.1
-- luaP_opnames[] is set above, as the luaP.opnames table
-- opmode(t,b,bk,ck,sa,k,m) deleted
--[[--------------------------------------------------------------------
Legend for luaP:opmodes:
1 T -> T (is a test?)
2 B -> B is a register
3 b -> B is an RK register/constant combination
4 C -> C is an RK register/constant combination
5 A -> register A is set by the opcode
6 K -> Bx is a constant
7 m -> 1 if iABC layout,
2 if iABx layout,
3 if iAsBx layout
----------------------------------------------------------------------]]
luaP.opmodes = {
-- TBbCAKm opcode
"0100101", -- OP_MOVE 0
"0000112", -- OP_LOADK
"0000101", -- OP_LOADBOOL
"0100101", -- OP_LOADNIL
"0000101", -- OP_GETUPVAL
"0000112", -- OP_GETGLOBAL 5
"0101101", -- OP_GETTABLE
"0000012", -- OP_SETGLOBAL
"0000001", -- OP_SETUPVAL
"0011001", -- OP_SETTABLE
"0000101", -- OP_NEWTABLE 10
"0101101", -- OP_SELF
"0011101", -- OP_ADD
"0011101", -- OP_SUB
"0011101", -- OP_MUL
"0011101", -- OP_DIV 15
"0011101", -- OP_MOD
"0011101", -- OP_POW
"0100101", -- OP_UNM
"0100101", -- OP_NOT
"0100101", -- OP_LEN 20
"0101101", -- OP_CONCAT
"0000003", -- OP_JMP
"1011001", -- OP_EQ
"1011001", -- OP_LT
"1011001", -- OP_LE 25
"1000101", -- OP_TEST
"1100101", -- OP_TESTSET
"0000001", -- OP_CALL
"0000001", -- OP_TAILCALL
"0000001", -- OP_RETURN 30
"0000003", -- OP_FORLOOP
"0000103", -- OP_FORPREP
"1000101", -- OP_TFORLOOP
"0000001", -- OP_SETLIST
"0000001", -- OP_CLOSE 35
"0000102", -- OP_CLOSURE
"0000101" -- OP_VARARG
}

View File

@@ -0,0 +1,60 @@
-- construct proper path to load metalua modules to build
-- an abstract syntax tree (AST)
local file = debug.getinfo(1, "S").source
if string.find(file, "@") == 1 then file = string.sub(file, 2) end
package.path = package.path .. ';' .. string.gsub(file, "metalua%.lua$", "?.lua")
-- these modules are sufficient to build an AST from a source file/string
require "lexer"
require "gg"
require "mlp_lexer"
require "mlp_misc"
require "mlp_table"
require "mlp_meta"
require "mlp_expr"
require "mlp_stat"
-- these modules are needed to convert an AST into bytecode to execute
require "lcode"
require "ldump"
require "lopcodes"
require "compile"
-- this is the compiler module that builds bytecode from an AST
local mlc = { }
function mlc.function_of_ast (ast)
local proto = bytecode.metalua_compile(ast)
local dump = bytecode.dump_string(proto)
local func = string.undump(dump)
return func
end
function mlc.ast_of_luastring (src, file)
local lx = mlp.lexer:newstream(src, file or "(string)")
local ast = mlp.chunk(lx)
return ast
end
function mlc.function_of_luastring (src, file)
local ast = mlc.ast_of_luastring(src, file)
local func = mlc.function_of_ast(ast)
return func
end
function mlc.function_of_luafile (name)
local f = io.open(name, 'r')
local src = f:read('*a')
f:close()
return mlc.function_of_luastring(src, "@"..name)
end
_G.mlc = mlc
--[[
-- Can be used with the following code:
require "metalua"
local ast = mlc.ast_of_luastring(src)
local f = mlc.function_of_ast(ast)
f()
]]

View File

@@ -0,0 +1,104 @@
----------------------------------------------------------------------
----------------------------------------------------------------------
--
-- Base library extension
--
----------------------------------------------------------------------
----------------------------------------------------------------------
if not metalua then rawset(getfenv(), 'metalua', { }) end
metalua.version = "v-0.5"
if not rawpairs then
rawpairs, rawipairs, rawtype = pairs, ipairs, type
end
function pairs(x)
assert(type(x)=='table', 'pairs() expects a table')
local mt = getmetatable(x)
if mt then
local mtp = mt.__pairs
if mtp then return mtp(x) end
end
return rawpairs(x)
end
function ipairs(x)
assert(type(x)=='table', 'ipairs() expects a table')
local mt = getmetatable(x)
if mt then
local mti = mt.__ipairs
if mti then return mti(x) end
end
return rawipairs(x)
end
--[[
function type(x)
local mt = getmetatable(x)
if mt then
local mtt = mt.__type
if mtt then return mtt end
end
return rawtype(x)
end
]]
function min (a, ...)
for n in values{...} do if n<a then a=n end end
return a
end
function max (a, ...)
for n in values{...} do if n>a then a=n end end
return a
end
function o (...)
local args = {...}
local function g (...)
local result = {...}
for i=#args, 1, -1 do result = {args[i](unpack(result))} end
return unpack (result)
end
return g
end
function id (...) return ... end
function const (k) return function () return k end end
function printf(...) return print(string.format(...)) end
function eprintf(...)
io.stderr:write(string.format(...).."\n")
end
function ivalues (x)
assert(type(x)=='table', 'ivalues() expects a table')
local i = 1
local function iterator ()
local r = x[i]; i=i+1; return r
end
return iterator
end
function values (x)
assert(type(x)=='table', 'values() expects a table')
local function iterator (state)
local it
state.content, it = next(state.list, state.content)
return it
end
return iterator, { list = x }
end
function keys (x)
assert(type(x)=='table', 'keys() expects a table')
local function iterator (state)
local it = next(state.list, state.content)
state.content = it
return it
end
return iterator, { list = x }
end

View File

@@ -0,0 +1,3 @@
require 'metalua.base'
require 'metalua.table2'
require 'metalua.string2'

View File

@@ -0,0 +1,43 @@
----------------------------------------------------------------------
----------------------------------------------------------------------
--
-- String module extension
--
----------------------------------------------------------------------
----------------------------------------------------------------------
-- Courtesy of lua-users.org
function string.split(str, pat)
local t = {}
local fpat = "(.-)" .. pat
local last_end = 1
local s, e, cap = string.find(str, fpat, 1)
while s do
if s ~= 1 or cap ~= "" then
table.insert(t,cap)
end
last_end = e+1
s, e, cap = string.find(str, fpat, last_end)
end
if last_end <= string.len(str) then
cap = string.sub(str, last_end)
table.insert(t, cap)
end
return t
end
-- "match" is regularly used as a keyword for pattern matching,
-- so here is an always available substitute.
string.strmatch = string["match"]
-- change a compiled string into a function
function string.undump(str)
if str:strmatch '^\027LuaQ' or str:strmatch '^#![^\n]+\n\027LuaQ' then
local f = (lua_loadstring or loadstring)(str)
return f
else
error "Not a chunk dump"
end
end
return string

View File

@@ -0,0 +1,380 @@
---------------------------------------------------------------------
----------------------------------------------------------------------
--
-- Table module extension
--
----------------------------------------------------------------------
----------------------------------------------------------------------
-- todo: table.scan (scan1?) fold1? flip?
function table.transpose(t)
local tt = { }
for a, b in pairs(t) do tt[b] = a end
return tt
end
function table.iforeach(f, ...)
-- assert (type (f) == "function") [wouldn't allow metamethod __call]
local nargs = select("#", ...)
if nargs==1 then -- Quick iforeach (most common case), just one table arg
local t = ...
assert (type (t) == "table")
for i = 1, #t do
local result = f (t[i])
-- If the function returns non-false, stop iteration
if result then return result end
end
else -- advanced case: boundaries and/or multiple tables
-- fargs: arguments fot a single call to f
-- first, last: indexes of the first & last elements mapped in each table
-- arg1: index of the first table in args
-- 1 - find boundaries if any
local args, fargs, first, last, arg1 = {...}, { }
if type(args[1]) ~= "number" then first, arg1 = 1, 1 -- no boundary
elseif type(args[2]) ~= "number" then first, last, arg1 = 1, args[1], 2
else first, last, arg1 = args[1], args[2], 3 end
assert (nargs >= arg1) -- at least one table
-- 2 - determine upper boundary if not given
if not last then for i = arg1, nargs do
assert (type (args[i]) == "table")
last = max (#args[i], last)
end end
-- 3 - remove non-table arguments from args, adjust nargs
if arg1>1 then args = { select(arg1, unpack(args)) }; nargs = #args end
-- 4 - perform the iteration
for i = first, last do
for j = 1, nargs do fargs[j] = args[j][i] end -- build args list
local result = f (unpack (fargs)) -- here is the call
-- If the function returns non-false, stop iteration
if result then return result end
end
end
end
function table.imap (f, ...)
local result, idx = { }, 1
local function g(...) result[idx] = f(...); idx=idx+1 end
table.iforeach(g, ...)
return result
end
function table.ifold (f, acc, ...)
local function g(...) acc = f (acc,...) end
table.iforeach (g, ...)
return acc
end
-- function table.ifold1 (f, ...)
-- return table.ifold (f, acc, 2, false, ...)
-- end
function table.izip(...)
local function g(...) return {...} end
return table.imap(g, ...)
end
function table.ifilter(f, t)
local yes, no = { }, { }
for i=1,#t do table.insert (f(t[i]) and yes or no, t[i]) end
return yes, no
end
function table.icat(...)
local result = { }
for t in values {...} do
for x in values (t) do
table.insert (result, x)
end
end
return result
end
function table.iflatten (x) return table.icat (unpack (x)) end
function table.irev (t)
local result, nt = { }, #t
for i=0, nt-1 do result[nt-i] = t[i+1] end
return result
end
function table.isub (t, ...)
local ti, u = table.insert, { }
local args, nargs = {...}, select("#", ...)
for i=1, nargs/2 do
local a, b = args[2*i-1], args[2*i]
for i=a, b, a<=b and 1 or -1 do ti(u, t[i]) end
end
return u
end
function table.iall (f, ...)
local result = true
local function g(...) return not f(...) end
return not table.iforeach(g, ...)
--return result
end
function table.iany (f, ...)
local function g(...) return not f(...) end
return not table.iall(g, ...)
end
function table.shallow_copy(x)
local y={ }
for k, v in pairs(x) do y[k]=v end
return y
end
-- Warning, this is implementation dependent: it relies on
-- the fact the [next()] enumerates the array-part before the hash-part.
function table.cat(...)
local y={ }
for x in values{...} do
-- cat array-part
for _, v in ipairs(x) do table.insert(y,v) end
-- cat hash-part
local lx, k = #x
if lx>0 then k=next(x,lx) else k=next(x) end
while k do y[k]=x[k]; k=next(x,k) end
end
return y
end
function table.deep_copy(x)
local tracker = { }
local function aux (x)
if type(x) == "table" then
local y=tracker[x]
if y then return y end
y = { }; tracker[x] = y
setmetatable (y, getmetatable (x))
for k,v in pairs(x) do y[aux(k)] = aux(v) end
return y
else return x end
end
return aux(x)
end
function table.override(dst, src)
for k, v in pairs(src) do dst[k] = v end
for i = #src+1, #dst do dst[i] = nil end
return dst
end
function table.range(a,b,c)
if not b then assert(not(c)); b=a; a=1
elseif not c then c = (b>=a) and 1 or -1 end
local result = { }
for i=a, b, c do table.insert(result, i) end
return result
end
-- FIXME: new_indent seems to be always nil?!
-- FIXME: accumulator function should be configurable,
-- so that print() doesn't need to bufferize the whole string
-- before starting to print.
function table.tostring(t, ...)
local PRINT_HASH, HANDLE_TAG, FIX_INDENT, LINE_MAX, INITIAL_INDENT = true, true
for _, x in ipairs {...} do
if type(x) == "number" then
if not LINE_MAX then LINE_MAX = x
else INITIAL_INDENT = x end
elseif x=="nohash" then PRINT_HASH = false
elseif x=="notag" then HANDLE_TAG = false
else
local n = string['match'](x, "^indent%s*(%d*)$")
if n then FIX_INDENT = tonumber(n) or 3 end
end
end
LINE_MAX = LINE_MAX or math.huge
INITIAL_INDENT = INITIAL_INDENT or 1
local current_offset = 0 -- indentation level
local xlen_cache = { } -- cached results for xlen()
local acc_list = { } -- Generated bits of string
local function acc(...) -- Accumulate a bit of string
local x = table.concat{...}
current_offset = current_offset + #x
table.insert(acc_list, x)
end
local function valid_id(x)
-- FIXME: we should also reject keywords; but the list of
-- current keywords is not fixed in metalua...
return type(x) == "string"
and string['match'](x, "^[a-zA-Z_][a-zA-Z0-9_]*$")
end
-- Compute the number of chars it would require to display the table
-- on a single line. Helps to decide whether some carriage returns are
-- required. Since the size of each sub-table is required many times,
-- it's cached in [xlen_cache].
local xlen_type = { }
local function xlen(x, nested)
nested = nested or { }
if x==nil then return #"nil" end
--if nested[x] then return #tostring(x) end -- already done in table
local len = xlen_cache[x]
if len then return len end
local f = xlen_type[type(x)]
if not f then return #tostring(x) end
len = f (x, nested)
xlen_cache[x] = len
return len
end
-- optim: no need to compute lengths if I'm not going to use them
-- anyway.
if LINE_MAX == math.huge then xlen = function() return 0 end end
xlen_type["nil"] = function () return 3 end
function xlen_type.number (x) return #tostring(x) end
function xlen_type.boolean (x) return x and 4 or 5 end
function xlen_type.string (x) return #string.format("%q",x) end
function xlen_type.table (adt, nested)
-- Circular references detection
if nested [adt] then return #tostring(adt) end
nested [adt] = true
local has_tag = HANDLE_TAG and valid_id(adt.tag)
local alen = #adt
local has_arr = alen>0
local has_hash = false
local x = 0
if PRINT_HASH then
-- first pass: count hash-part
for k, v in pairs(adt) do
if k=="tag" and has_tag then
-- this is the tag -> do nothing!
elseif type(k)=="number" and k<=alen and math.fmod(k,1)==0 then
-- array-part pair -> do nothing!
else
has_hash = true
if valid_id(k) then x=x+#k
else x = x + xlen (k, nested) + 2 end -- count surrounding brackets
x = x + xlen (v, nested) + 5 -- count " = " and ", "
end
end
end
for i = 1, alen do x = x + xlen (adt[i], nested) + 2 end -- count ", "
nested[adt] = false -- No more nested calls
if not (has_tag or has_arr or has_hash) then return 3 end
if has_tag then x=x+#adt.tag+1 end
if not (has_arr or has_hash) then return x end
if not has_hash and alen==1 and type(adt[1])~="table" then
return x-2 -- substract extraneous ", "
end
return x+2 -- count "{ " and " }", substract extraneous ", "
end
-- Recursively print a (sub) table at given indentation level.
-- [newline] indicates whether newlines should be inserted.
local function rec (adt, nested, indent)
if not FIX_INDENT then indent = current_offset end
local function acc_newline()
acc ("\n"); acc (string.rep (" ", indent))
current_offset = indent
end
local x = { }
x["nil"] = function() acc "nil" end
function x.number() acc (tostring (adt)) end
--function x.string() acc (string.format ("%q", adt)) end
function x.string() acc ((string.format ("%q", adt):gsub("\\\n", "\\n"))) end
function x.boolean() acc (adt and "true" or "false") end
function x.table()
if nested[adt] then acc(tostring(adt)); return end
nested[adt] = true
local has_tag = HANDLE_TAG and valid_id(adt.tag)
local alen = #adt
local has_arr = alen>0
local has_hash = false
if has_tag then acc("`"); acc(adt.tag) end
-- First pass: handle hash-part
if PRINT_HASH then
for k, v in pairs(adt) do
-- pass if the key belongs to the array-part or is the "tag" field
if not (k=="tag" and HANDLE_TAG) and
not (type(k)=="number" and k<=alen and math.fmod(k,1)==0) then
-- Is it the first time we parse a hash pair?
if not has_hash then
acc "{ "
if not FIX_INDENT then indent = current_offset end
else acc ", " end
-- Determine whether a newline is required
local is_id, expected_len = valid_id(k)
if is_id then expected_len = #k + xlen (v, nested) + #" = , "
else expected_len = xlen (k, nested) +
xlen (v, nested) + #"[] = , " end
if has_hash and expected_len + current_offset > LINE_MAX
then acc_newline() end
-- Print the key
if is_id then acc(k); acc " = "
else acc "["; rec (k, nested, indent+(FIX_INDENT or 0)); acc "] = " end
-- Print the value
rec (v, nested, indent+(FIX_INDENT or 0))
has_hash = true
end
end
end
-- Now we know whether there's a hash-part, an array-part, and a tag.
-- Tag and hash-part are already printed if they're present.
if not has_tag and not has_hash and not has_arr then acc "{ }";
elseif has_tag and not has_hash and not has_arr then -- nothing, tag already in acc
else
assert (has_hash or has_arr)
local no_brace = false
if has_hash and has_arr then acc ", "
elseif has_tag and not has_hash and alen==1 and type(adt[1])~="table" then
-- No brace required; don't print "{", remember not to print "}"
acc (" "); rec (adt[1], nested, indent+(FIX_INDENT or 0))
no_brace = true
elseif not has_hash then
-- Braces required, but not opened by hash-part handler yet
acc "{ "
if not FIX_INDENT then indent = current_offset end
end
-- 2nd pass: array-part
if not no_brace and has_arr then
rec (adt[1], nested, indent+(FIX_INDENT or 0))
for i=2, alen do
acc ", ";
if current_offset + xlen (adt[i], { }) > LINE_MAX
then acc_newline() end
rec (adt[i], nested, indent+(FIX_INDENT or 0))
end
end
if not no_brace then acc " }" end
end
nested[adt] = false -- No more nested calls
end
local y = x[type(adt)]
if y then y() else acc(tostring(adt)) end
end
--printf("INITIAL_INDENT = %i", INITIAL_INDENT)
current_offset = INITIAL_INDENT or 0
rec(t, { }, 0)
return table.concat (acc_list)
end
function table.print(...) return print(table.tostring(...)) end
return table

View File

@@ -0,0 +1,213 @@
----------------------------------------------------------------------
-- Metalua: $Id: mlp_expr.lua,v 1.7 2006/11/15 09:07:50 fab13n Exp $
--
-- Summary: metalua parser, expression parser. This is part of the
-- definition of module [mlp].
--
----------------------------------------------------------------------
--
-- Copyright (c) 2006, Fabien Fleutot <metalua@gmail.com>.
--
-- This software is released under the MIT Licence, see licence.txt
-- for details.
--
----------------------------------------------------------------------
-- History:
-- $Log: mlp_expr.lua,v $
-- Revision 1.7 2006/11/15 09:07:50 fab13n
-- debugged meta operators.
-- Added command line options handling.
--
-- Revision 1.6 2006/11/10 02:11:17 fab13n
-- compiler faithfulness to 5.1 improved
-- gg.expr extended
-- mlp.expr refactored
--
-- Revision 1.5 2006/11/09 09:39:57 fab13n
-- some cleanup
--
-- Revision 1.4 2006/11/07 21:29:02 fab13n
-- improved quasi-quoting
--
-- Revision 1.3 2006/11/07 04:38:00 fab13n
-- first bootstrapping version.
--
-- Revision 1.2 2006/11/05 15:08:34 fab13n
-- updated code generation, to be compliant with 5.1
--
----------------------------------------------------------------------
--------------------------------------------------------------------------------
--
-- Exported API:
-- * [mlp.expr()]
-- * [mlp.expr_list()]
-- * [mlp.func_val()]
--
--------------------------------------------------------------------------------
--require "gg"
--require "mlp_misc"
--require "mlp_table"
--require "mlp_meta"
--------------------------------------------------------------------------------
-- These function wrappers (eta-expansions ctually) are just here to break
-- some circular dependencies between mlp_xxx.lua files.
--------------------------------------------------------------------------------
local function _expr (lx) return mlp.expr (lx) end
local function _table_content (lx) return mlp.table_content (lx) end
local function block (lx) return mlp.block (lx) end
local function stat (lx) return mlp.stat (lx) end
module ("mlp", package.seeall)
--------------------------------------------------------------------------------
-- Non-empty expression list. Actually, this isn't used here, but that's
-- handy to give to users.
--------------------------------------------------------------------------------
expr_list = gg.list{ _expr, separators = "," }
--------------------------------------------------------------------------------
-- Helpers for function applications / method applications
--------------------------------------------------------------------------------
func_args_content = gg.list {
name = "function arguments",
_expr, separators = ",", terminators = ")" }
-- Used to parse methods
method_args = gg.multisequence{
name = "function argument(s)",
{ "{", table_content, "}" },
{ "(", func_args_content, ")", builder = fget(1) },
{ "+{", quote_content, "}" },
function(lx) local r = opt_string(lx); return r and {r} or { } end }
--------------------------------------------------------------------------------
-- [func_val] parses a function, from opening parameters parenthese to
-- "end" keyword included. Used for anonymous functions as well as
-- function declaration statements (both local and global).
--
-- It's wrapped in a [_func_val] eta expansion, so that when expr
-- parser uses the latter, they will notice updates of [func_val]
-- definitions.
--------------------------------------------------------------------------------
func_params_content = gg.list{ name="function parameters",
gg.multisequence{ { "...", builder = "Dots" }, id },
separators = ",", terminators = {")", "|"} }
local _func_params_content = function (lx) return func_params_content(lx) end
func_val = gg.sequence { name="function body",
"(", func_params_content, ")", block, "end", builder = "Function" }
local _func_val = function (lx) return func_val(lx) end
--------------------------------------------------------------------------------
-- Default parser for primary expressions
--------------------------------------------------------------------------------
function id_or_literal (lx)
local a = lx:next()
if a.tag~="Id" and a.tag~="String" and a.tag~="Number" then
local msg
if a.tag=='Eof' then
msg = "End of file reached when an expression was expected"
elseif a.tag=='Keyword' then
msg = "An expression was expected, and `"..a[1]..
"' can't start an expression"
else
msg = "Unexpected expr token " .. _G.table.tostring (a, 'nohash')
end
gg.parse_error (lx, msg)
end
return a
end
--------------------------------------------------------------------------------
-- Builder generator for operators. Wouldn't be worth it if "|x|" notation
-- were allowed, but then lua 5.1 wouldn't compile it
--------------------------------------------------------------------------------
-- opf1 = |op| |_,a| `Op{ op, a }
local function opf1 (op) return
function (_,a) return { tag="Op", op, a } end end
-- opf2 = |op| |a,_,b| `Op{ op, a, b }
local function opf2 (op) return
function (a,_,b) return { tag="Op", op, a, b } end end
-- opf2r = |op| |a,_,b| `Op{ op, b, a } -- (args reversed)
local function opf2r (op) return
function (a,_,b) return { tag="Op", op, b, a } end end
local function op_ne(a, _, b)
-- The first version guarantees to return the same code as Lua,
-- but it relies on the non-standard 'ne' operator, which has been
-- suppressed from the official AST grammar (although still supported
-- in practice by the compiler).
-- return { tag="Op", "ne", a, b }
return { tag="Op", "not", { tag="Op", "eq", a, b, lineinfo= {
first = a.lineinfo.first, last = b.lineinfo.last } } }
end
--------------------------------------------------------------------------------
--
-- complete expression
--
--------------------------------------------------------------------------------
-- FIXME: set line number. In [expr] transformers probably
expr = gg.expr { name = "expression",
primary = gg.multisequence{ name="expr primary",
{ "(", _expr, ")", builder = "Paren" },
{ "function", _func_val, builder = fget(1) },
{ "-{", splice_content, "}", builder = fget(1) },
{ "+{", quote_content, "}", builder = fget(1) },
{ "nil", builder = "Nil" },
{ "true", builder = "True" },
{ "false", builder = "False" },
{ "...", builder = "Dots" },
table,
id_or_literal },
infix = { name="expr infix op",
{ "+", prec = 60, builder = opf2 "add" },
{ "-", prec = 60, builder = opf2 "sub" },
{ "*", prec = 70, builder = opf2 "mul" },
{ "/", prec = 70, builder = opf2 "div" },
{ "%", prec = 70, builder = opf2 "mod" },
{ "^", prec = 90, builder = opf2 "pow", assoc = "right" },
{ "..", prec = 40, builder = opf2 "concat", assoc = "right" },
{ "==", prec = 30, builder = opf2 "eq" },
{ "~=", prec = 30, builder = op_ne },
{ "<", prec = 30, builder = opf2 "lt" },
{ "<=", prec = 30, builder = opf2 "le" },
{ ">", prec = 30, builder = opf2r "lt" },
{ ">=", prec = 30, builder = opf2r "le" },
{ "and",prec = 20, builder = opf2 "and" },
{ "or", prec = 10, builder = opf2 "or" } },
prefix = { name="expr prefix op",
{ "not", prec = 80, builder = opf1 "not" },
{ "#", prec = 80, builder = opf1 "len" },
{ "-", prec = 80, builder = opf1 "unm" } },
suffix = { name="expr suffix op",
{ "[", _expr, "]", builder = function (tab, idx)
return {tag="Index", tab, idx[1]} end},
{ ".", id, builder = function (tab, field)
return {tag="Index", tab, id2string(field[1])} end },
{ "(", func_args_content, ")", builder = function(f, args)
return {tag="Call", f, unpack(args[1])} end },
{ "{", _table_content, "}", builder = function (f, arg)
return {tag="Call", f, arg[1]} end},
{ ":", id, method_args, builder = function (obj, post)
return {tag="Invoke", obj, id2string(post[1]), unpack(post[2])} end},
{ "+{", quote_content, "}", builder = function (f, arg)
return {tag="Call", f, arg[1] } end },
default = { name="opt_string_arg", parse = mlp.opt_string, builder = function(f, arg)
return {tag="Call", f, arg } end } } }

View File

@@ -0,0 +1,89 @@
--------------------------------------------------------------------------------
--
-- Non-Lua syntax extensions
--
--------------------------------------------------------------------------------
module ("mlp", package.seeall)
--------------------------------------------------------------------------------
-- Alebraic Datatypes
--------------------------------------------------------------------------------
local function adt (lx)
local tagval = id (lx) [1]
local tagkey = {tag="Pair", {tag="String", "tag"}, {tag="String", tagval} }
if lx:peek().tag == "String" or lx:peek().tag == "Number" then
return { tag="Table", tagkey, lx:next() }
elseif lx:is_keyword (lx:peek(), "{") then
local x = table (lx)
_G.table.insert (x, 1, tagkey)
return x
else return { tag="Table", tagkey } end
end
expr:add{ "`", adt, builder = fget(1) }
--------------------------------------------------------------------------------
-- Anonymous lambda
--------------------------------------------------------------------------------
local lambda_expr = gg.sequence{
"|", func_params_content, "|", expr,
builder= function (x)
local li = x[2].lineinfo
return { tag="Function", x[1],
{ {tag="Return", x[2], lineinfo=li }, lineinfo=li } }
end }
-- In an earlier version, lambda_expr took an expr_list rather than an expr
-- after the 2nd bar. However, it happened to be much more of a burden than an
-- help, So finally I disabled it. If you want to return several results,
-- use the long syntax.
--------------------------------------------------------------------------------
-- local lambda_expr = gg.sequence{
-- "|", func_params_content, "|", expr_list,
-- builder= function (x)
-- return {tag="Function", x[1], { {tag="Return", unpack(x[2]) } } } end }
expr:add (lambda_expr)
--------------------------------------------------------------------------------
-- Allows to write "a `f` b" instead of "f(a, b)". Taken from Haskell.
-- This is not part of Lua 5.1 syntax, so it's added to the expression
-- afterwards, so that it's easier to disable.
--------------------------------------------------------------------------------
local function expr_in_backquotes (lx) return expr(lx, 35) end
expr.infix:add{ name = "infix function",
"`", expr_in_backquotes, "`", prec = 35, assoc="left",
builder = function(a, op, b) return {tag="Call", op[1], a, b} end }
--------------------------------------------------------------------------------
-- table.override assignment
--------------------------------------------------------------------------------
mlp.lexer:add "<-"
stat.assignments["<-"] = function (a, b)
assert( #a==1 and #b==1, "No multi-args for '<-'")
return { tag="Call", { tag="Index", { tag="Id", "table" },
{ tag="String", "override" } },
a[1], b[1]}
end
--------------------------------------------------------------------------------
-- C-style op+assignments
--------------------------------------------------------------------------------
local function op_assign(kw, op)
local function rhs(a, b)
return { tag="Op", op, a, b }
end
local function f(a,b)
return { tag="Set", a, _G.table.imap(rhs, a, b) }
end
mlp.lexer:add (kw)
mlp.stat.assignments[kw] = f
end
_G.table.iforeach (op_assign,
{"+=", "-=", "*=", "/="},
{"add", "sub", "mul", "div"})

View File

@@ -0,0 +1,32 @@
----------------------------------------------------------------------
-- Metalua: $Id: mll.lua,v 1.3 2006/11/15 09:07:50 fab13n Exp $
--
-- Summary: Source file lexer. ~~Currently only works on strings.
-- Some API refactoring is needed.
--
----------------------------------------------------------------------
--
-- Copyright (c) 2006-2007, Fabien Fleutot <metalua@gmail.com>.
--
-- This software is released under the MIT Licence, see licence.txt
-- for details.
--
----------------------------------------------------------------------
module ("mlp", package.seeall)
require "lexer"
local mlp_lexer = lexer.lexer:clone()
local keywords = {
"and", "break", "do", "else", "elseif",
"end", "false", "for", "function", "if",
"in", "local", "nil", "not", "or", "repeat",
"return", "then", "true", "until", "while",
"...", "..", "==", ">=", "<=", "~=",
"+{", "-{" }
for w in values(keywords) do mlp_lexer:add(w) end
_M.lexer = mlp_lexer

View File

@@ -0,0 +1,118 @@
----------------------------------------------------------------------
-- Metalua: $Id: mlp_meta.lua,v 1.4 2006/11/15 09:07:50 fab13n Exp $
--
-- Summary: Meta-operations: AST quasi-quoting and splicing
--
----------------------------------------------------------------------
--
-- Copyright (c) 2006, Fabien Fleutot <metalua@gmail.com>.
--
-- This software is released under the MIT Licence, see licence.txt
-- for details.
--
----------------------------------------------------------------------
--------------------------------------------------------------------------------
--
-- Exported API:
-- * [mlp.splice_content()]
-- * [mlp.quote_content()]
--
--------------------------------------------------------------------------------
module ("mlp", package.seeall)
--------------------------------------------------------------------------------
-- External splicing: compile an AST into a chunk, load and evaluate
-- that chunk, and replace the chunk by its result (which must also be
-- an AST).
--------------------------------------------------------------------------------
function splice (ast)
local f = mlc.function_of_ast(ast, '=splice')
local result=f()
return result
end
--------------------------------------------------------------------------------
-- Going from an AST to an AST representing that AST
-- the only key being lifted in this version is ["tag"]
--------------------------------------------------------------------------------
function quote (t)
--print("QUOTING:", _G.table.tostring(t, 60))
local cases = { }
function cases.table (t)
local mt = { tag = "Table" }
--_G.table.insert (mt, { tag = "Pair", quote "quote", { tag = "True" } })
if t.tag == "Splice" then
assert (#t==1, "Invalid splice")
local sp = t[1]
return sp
elseif t.tag then
_G.table.insert (mt, { tag = "Pair", quote "tag", quote (t.tag) })
end
for _, v in ipairs (t) do
_G.table.insert (mt, quote(v))
end
return mt
end
function cases.number (t) return { tag = "Number", t, quote = true } end
function cases.string (t) return { tag = "String", t, quote = true } end
return cases [ type (t) ] (t)
end
--------------------------------------------------------------------------------
-- when this variable is false, code inside [-{...}] is compiled and
-- avaluated immediately. When it's true (supposedly when we're
-- parsing data inside a quasiquote), [-{foo}] is replaced by
-- [`Splice{foo}], which will be unpacked by [quote()].
--------------------------------------------------------------------------------
in_a_quote = false
--------------------------------------------------------------------------------
-- Parse the inside of a "-{ ... }"
--------------------------------------------------------------------------------
function splice_content (lx)
local parser_name = "expr"
if lx:is_keyword (lx:peek(2), ":") then
local a = lx:next()
lx:next() -- skip ":"
assert (a.tag=="Id", "Invalid splice parser name")
parser_name = a[1]
end
local ast = mlp[parser_name](lx)
if in_a_quote then
--printf("SPLICE_IN_QUOTE:\n%s", _G.table.tostring(ast, "nohash", 60))
return { tag="Splice", ast }
else
if parser_name == "expr" then ast = { { tag="Return", ast } }
elseif parser_name == "stat" then ast = { ast }
elseif parser_name ~= "block" then
error ("splice content must be an expr, stat or block") end
--printf("EXEC THIS SPLICE:\n%s", _G.table.tostring(ast, "nohash", 60))
return splice (ast)
end
end
--------------------------------------------------------------------------------
-- Parse the inside of a "+{ ... }"
--------------------------------------------------------------------------------
function quote_content (lx)
local parser
if lx:is_keyword (lx:peek(2), ":") then -- +{parser: content }
parser = mlp[id(lx)[1]]
lx:next()
else -- +{ content }
parser = mlp.expr
end
local prev_iq = in_a_quote
in_a_quote = true
--print("IN_A_QUOTE")
local content = parser (lx)
local q_content = quote (content)
in_a_quote = prev_iq
return q_content
end

View File

@@ -0,0 +1,185 @@
----------------------------------------------------------------------
-- Metalua: $Id: mlp_misc.lua,v 1.6 2006/11/15 09:07:50 fab13n Exp $
--
-- Summary: metalua parser, miscellaneous utility functions.
--
----------------------------------------------------------------------
--
-- Copyright (c) 2006, Fabien Fleutot <metalua@gmail.com>.
--
-- This software is released under the MIT Licence, see licence.txt
-- for details.
--
----------------------------------------------------------------------
-- History:
-- $Log: mlp_misc.lua,v $
-- Revision 1.6 2006/11/15 09:07:50 fab13n
-- debugged meta operators.
-- Added command line options handling.
--
-- Revision 1.5 2006/11/10 02:11:17 fab13n
-- compiler faithfulness to 5.1 improved
-- gg.expr extended
-- mlp.expr refactored
--
-- Revision 1.4 2006/11/09 09:39:57 fab13n
-- some cleanup
--
-- Revision 1.3 2006/11/07 04:38:00 fab13n
-- first bootstrapping version.
--
-- Revision 1.2 2006/11/05 15:08:34 fab13n
-- updated code generation, to be compliant with 5.1
--
----------------------------------------------------------------------
--------------------------------------------------------------------------------
--
-- Exported API:
-- * [mlp.fget()]
-- * [mlp.id()]
-- * [mlp.opt_id()]
-- * [mlp.id_list()]
-- * [mlp.gensym()]
-- * [mlp.string()]
-- * [mlp.opt_string()]
-- * [mlp.id2string()]
--
--------------------------------------------------------------------------------
--require "gg"
--require "mll"
module ("mlp", package.seeall)
--------------------------------------------------------------------------------
-- returns a function that takes the [n]th element of a table.
-- if [tag] is provided, then this element is expected to be a
-- table, and this table receives a "tag" field whose value is
-- set to [tag].
--
-- The primary purpose of this is to generate builders for
-- grammar generators. It has little purpose in metalua, as lambda has
-- a lightweight syntax.
--------------------------------------------------------------------------------
function fget (n, tag)
assert (type (n) == "number")
if tag then
assert (type (tag) == "string")
return function (x)
assert (type (x[n]) == "table")
return {tag=tag, unpack(x[n])} end
else
return function (x) return x[n] end
end
end
--------------------------------------------------------------------------------
-- Try to read an identifier (possibly as a splice), or return [false] if no
-- id is found.
--------------------------------------------------------------------------------
function opt_id (lx)
local a = lx:peek();
if lx:is_keyword (a, "-{") then
local v = gg.sequence{ "-{", splice_content, "}" } (lx) [1]
if v.tag ~= "Id" and v.tag ~= "Splice" then
gg.parse_error(lx,"Bad id splice")
end
return v
elseif a.tag == "Id" then return lx:next()
else return false end
end
--------------------------------------------------------------------------------
-- Mandatory reading of an id: causes an error if it can't read one.
--------------------------------------------------------------------------------
function id (lx)
return opt_id (lx) or gg.parse_error(lx,"Identifier expected")
end
--------------------------------------------------------------------------------
-- Common helper function
--------------------------------------------------------------------------------
id_list = gg.list { primary = mlp.id, separators = "," }
--------------------------------------------------------------------------------
-- Symbol generator: [gensym()] returns a guaranteed-to-be-unique identifier.
-- The main purpose is to avoid variable capture in macros.
--
-- If a string is passed as an argument, theis string will be part of the
-- id name (helpful for macro debugging)
--------------------------------------------------------------------------------
local gensymidx = 0
function gensym (arg)
gensymidx = gensymidx + 1
return { tag="Id", _G.string.format(".%i.%s", gensymidx, arg or "")}
end
--------------------------------------------------------------------------------
-- Converts an identifier into a string. Hopefully one day it'll handle
-- splices gracefully, but that proves quite tricky.
--------------------------------------------------------------------------------
function id2string (id)
--print("id2string:", disp.ast(id))
if id.tag == "Id" then id.tag = "String"; return id
elseif id.tag == "Splice" then
assert (in_a_quote, "can't do id2string on an outermost splice")
error ("id2string on splice not implemented")
-- Evaluating id[1] will produce `Id{ xxx },
-- and we want it to produce `String{ xxx }
-- Morally, this is what I want:
-- return `String{ `Index{ `Splice{ id[1] }, `Number 1 } }
-- That is, without sugar:
return {tag="String", {tag="Index", {tag="Splice", id[1] },
{tag="Number", 1 } } }
else error ("Identifier expected: ".._G.table.tostring(id, 'nohash')) end
end
--------------------------------------------------------------------------------
-- Read a string, possibly spliced, or return an error if it can't
--------------------------------------------------------------------------------
function string (lx)
local a = lx:peek()
if lx:is_keyword (a, "-{") then
local v = gg.sequence{ "-{", splice_content, "}" } (lx) [1]
if v.tag ~= "" and v.tag ~= "Splice" then
gg.parse_error(lx,"Bad string splice")
end
return v
elseif a.tag == "String" then return lx:next()
else error "String expected" end
end
--------------------------------------------------------------------------------
-- Try to read a string, or return false if it can't. No splice allowed.
--------------------------------------------------------------------------------
function opt_string (lx)
return lx:peek().tag == "String" and lx:next()
end
--------------------------------------------------------------------------------
-- Chunk reader: block + Eof
--------------------------------------------------------------------------------
function skip_initial_sharp_comment (lx)
-- Dirty hack: I'm happily fondling lexer's private parts
-- FIXME: redundant with lexer:newstream()
lx :sync()
local i = lx.src:match ("^#.-\n()", lx.i)
if i then lx.i, lx.column_offset, lx.line = i, i, lx.line+1 end
end
local function _chunk (lx)
if lx:peek().tag == 'Eof' then return { } -- handle empty files
else
skip_initial_sharp_comment (lx)
local chunk = block (lx)
if lx:peek().tag ~= "Eof" then error "End-of-file expected" end
return chunk
end
end
-- chunk is wrapped in a sequence so that it has a "transformer" field.
chunk = gg.sequence { _chunk, builder = unpack }

View File

@@ -0,0 +1,226 @@
----------------------------------------------------------------------
-- Metalua: $Id: mlp_stat.lua,v 1.7 2006/11/15 09:07:50 fab13n Exp $
--
-- Summary: metalua parser, statement/block parser. This is part of
-- the definition of module [mlp].
--
----------------------------------------------------------------------
--
-- Copyright (c) 2006, Fabien Fleutot <metalua@gmail.com>.
--
-- This software is released under the MIT Licence, see licence.txt
-- for details.
--
----------------------------------------------------------------------
--
----------------------------------------------------------------------
--------------------------------------------------------------------------------
--
-- Exports API:
-- * [mlp.stat()]
-- * [mlp.block()]
-- * [mlp.for_header()]
--
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-- eta-expansions to break circular dependency
--------------------------------------------------------------------------------
local expr = function (lx) return mlp.expr (lx) end
local func_val = function (lx) return mlp.func_val (lx) end
local expr_list = function (lx) return mlp.expr_list(lx) end
module ("mlp", package.seeall)
--------------------------------------------------------------------------------
-- List of all keywords that indicate the end of a statement block. Users are
-- likely to extend this list when designing extensions.
--------------------------------------------------------------------------------
local block_terminators = { "else", "elseif", "end", "until", ")", "}", "]" }
-- FIXME: this must be handled from within GG!!!
function block_terminators:add(x)
if type (x) == "table" then for _, y in ipairs(x) do self:add (y) end
else _G.table.insert (self, x) end
end
--------------------------------------------------------------------------------
-- list of statements, possibly followed by semicolons
--------------------------------------------------------------------------------
block = gg.list {
name = "statements block",
terminators = block_terminators,
primary = function (lx)
-- FIXME use gg.optkeyword()
local x = stat (lx)
if lx:is_keyword (lx:peek(), ";") then lx:next() end
return x
end }
--------------------------------------------------------------------------------
-- Helper function for "return <expr_list>" parsing.
-- Called when parsing return statements.
-- The specific test for initial ";" is because it's not a block terminator,
-- so without itgg.list would choke on "return ;" statements.
-- We don't make a modified copy of block_terminators because this list
-- is sometimes modified at runtime, and the return parser would get out of
-- sync if it was relying on a copy.
--------------------------------------------------------------------------------
local return_expr_list_parser = gg.multisequence{
{ ";" , builder = function() return { } end },
default = gg.list {
expr, separators = ",", terminators = block_terminators } }
--------------------------------------------------------------------------------
-- for header, between [for] and [do] (exclusive).
-- Return the `Forxxx{...} AST, without the body element (the last one).
--------------------------------------------------------------------------------
function for_header (lx)
local var = mlp.id (lx)
if lx:is_keyword (lx:peek(), "=") then
-- Fornum: only 1 variable
lx:next() -- skip "="
local e = expr_list (lx)
assert (2 <= #e and #e <= 3, "2 or 3 values in a fornum")
return { tag="Fornum", var, unpack (e) }
else
-- Forin: there might be several vars
local a = lx:is_keyword (lx:next(), ",", "in")
if a=="in" then var_list = { var, lineinfo = var.lineinfo } else
-- several vars; first "," skipped, read other vars
var_list = gg.list{
primary = id, separators = ",", terminators = "in" } (lx)
_G.table.insert (var_list, 1, var) -- put back the first variable
lx:next() -- skip "in"
end
local e = expr_list (lx)
return { tag="Forin", var_list, e }
end
end
--------------------------------------------------------------------------------
-- Function def parser helper: id ( . id ) *
--------------------------------------------------------------------------------
local function fn_builder (list)
local r = list[1]
for i = 2, #list do r = { tag="Index", r, id2string(list[i]) } end
return r
end
local func_name = gg.list{ id, separators = ".", builder = fn_builder }
--------------------------------------------------------------------------------
-- Function def parser helper: ( : id )?
--------------------------------------------------------------------------------
local method_name = gg.onkeyword{ name = "method invocation", ":", id,
transformers = { function(x) return x and id2string(x) end } }
--------------------------------------------------------------------------------
-- Function def builder
--------------------------------------------------------------------------------
local function funcdef_builder(x)
local name, method, func = x[1], x[2], x[3]
if method then
name = { tag="Index", name, method, lineinfo = {
first = name.lineinfo.first,
last = method.lineinfo.last } }
_G.table.insert (func[1], 1, {tag="Id", "self"})
end
local r = { tag="Set", {name}, {func} }
r[1].lineinfo = name.lineinfo
r[2].lineinfo = func.lineinfo
return r
end
--------------------------------------------------------------------------------
-- if statement builder
--------------------------------------------------------------------------------
local function if_builder (x)
local cb_pairs, else_block, r = x[1], x[2], {tag="If"}
for i=1,#cb_pairs do r[2*i-1]=cb_pairs[i][1]; r[2*i]=cb_pairs[i][2] end
if else_block then r[#r+1] = else_block end
return r
end
--------------------------------------------------------------------------------
-- produce a list of (expr,block) pairs
--------------------------------------------------------------------------------
local elseifs_parser = gg.list {
gg.sequence { expr, "then", block },
separators = "elseif",
terminators = { "else", "end" } }
--------------------------------------------------------------------------------
-- assignments and calls: statements that don't start with a keyword
--------------------------------------------------------------------------------
local function assign_or_call_stat_parser (lx)
local e = expr_list (lx)
local a = lx:is_keyword(lx:peek())
local op = a and stat.assignments[a]
if op then
--FIXME: check that [e] is a LHS
lx:next()
local v = expr_list (lx)
if type(op)=="string" then return { tag=op, e, v }
else return op (e, v) end
else
assert (#e > 0)
if #e > 1 then
gg.parse_error (lx,
"comma is not a valid statement separator; statement can be "..
"separated by semicolons, or not separated at all") end
if e[1].tag ~= "Call" and e[1].tag ~= "Invoke" then
local typename
if e[1].tag == 'Id' then
typename = '("'..e[1][1]..'") is an identifier'
elseif e[1].tag == 'Op' then
typename = "is an arithmetic operation"
else typename = "is of type '"..(e[1].tag or "<list>").."'" end
gg.parse_error (lx, "This expression " .. typename ..
"; a statement was expected, and only function and method call "..
"expressions can be used as statements");
end
return e[1]
end
end
local_stat_parser = gg.multisequence{
-- local function <name> <func_val>
{ "function", id, func_val, builder =
function(x)
local vars = { x[1], lineinfo = x[1].lineinfo }
local vals = { x[2], lineinfo = x[2].lineinfo }
return { tag="Localrec", vars, vals }
end },
-- local <id_list> ( = <expr_list> )?
default = gg.sequence{ id_list, gg.onkeyword{ "=", expr_list },
builder = function(x) return {tag="Local", x[1], x[2] or { } } end } }
--------------------------------------------------------------------------------
-- statement
--------------------------------------------------------------------------------
stat = gg.multisequence {
name="statement",
{ "do", block, "end", builder =
function (x) return { tag="Do", unpack (x[1]) } end },
{ "for", for_header, "do", block, "end", builder =
function (x) x[1][#x[1]+1] = x[2]; return x[1] end },
{ "function", func_name, method_name, func_val, builder=funcdef_builder },
{ "while", expr, "do", block, "end", builder = "While" },
{ "repeat", block, "until", expr, builder = "Repeat" },
{ "local", local_stat_parser, builder = fget (1) },
{ "return", return_expr_list_parser, builder = fget (1, "Return") },
{ "break", builder = function() return { tag="Break" } end },
{ "-{", splice_content, "}", builder = fget(1) },
{ "if", elseifs_parser, gg.onkeyword{ "else", block }, "end",
builder = if_builder },
default = assign_or_call_stat_parser }
stat.assignments = {
["="] = "Set" }
function stat.assignments:add(k, v) self[k] = v end

View File

@@ -0,0 +1,92 @@
----------------------------------------------------------------------
-- Metalua: $Id: mlp_table.lua,v 1.5 2006/11/10 02:11:17 fab13n Exp $
--
-- Summary: metalua parser, table constructor parser. This is part
-- of thedefinition of module [mlp].
--
----------------------------------------------------------------------
--
-- Copyright (c) 2006, Fabien Fleutot <metalua@gmail.com>.
--
-- This software is released under the MIT Licence, see licence.txt
-- for details.
--
----------------------------------------------------------------------
-- History:
-- $Log: mlp_table.lua,v $
-- Revision 1.5 2006/11/10 02:11:17 fab13n
-- compiler faithfulness to 5.1 improved
-- gg.expr extended
-- mlp.expr refactored
--
-- Revision 1.4 2006/11/09 09:39:57 fab13n
-- some cleanup
--
-- Revision 1.3 2006/11/07 04:38:00 fab13n
-- first bootstrapping version.
--
-- Revision 1.2 2006/11/05 15:08:34 fab13n
-- updated code generation, to be compliant with 5.1
--
----------------------------------------------------------------------
--------------------------------------------------------------------------------
--
-- Exported API:
-- * [mlp.table_field()]
-- * [mlp.table_content()]
-- * [mlp.table()]
--
-- KNOWN BUG: doesn't handle final ";" or "," before final "}"
--
--------------------------------------------------------------------------------
--require "gg"
--require "mll"
--require "mlp_misc"
module ("mlp", package.seeall)
--------------------------------------------------------------------------------
-- eta expansion to break circular dependencies:
--------------------------------------------------------------------------------
local function _expr (lx) return expr(lx) end
--------------------------------------------------------------------------------
-- [[key] = value] table field definition
--------------------------------------------------------------------------------
local bracket_field = gg.sequence{ "[", _expr, "]", "=", _expr, builder = "Pair" }
--------------------------------------------------------------------------------
-- [id = value] or [value] table field definition;
-- [[key]=val] are delegated to [bracket_field()]
--------------------------------------------------------------------------------
function table_field (lx)
if lx:is_keyword (lx:peek(), "[") then return bracket_field (lx) end
local e = _expr (lx)
if lx:is_keyword (lx:peek(), "=") then
lx:next(); -- skip the "="
local key = id2string(e)
local val = _expr(lx)
local r = { tag="Pair", key, val }
r.lineinfo = { first = key.lineinfo.first, last = val.lineinfo.last }
return r
else return e end
end
local function _table_field(lx) return table_field(lx) end
--------------------------------------------------------------------------------
-- table constructor, without enclosing braces; returns a full table object
--------------------------------------------------------------------------------
table_content = gg.list { _table_field,
separators = { ",", ";" }, terminators = "}", builder = "Table" }
local function _table_content(lx) return table_content(lx) end
--------------------------------------------------------------------------------
-- complete table constructor including [{...}]
--------------------------------------------------------------------------------
table = gg.sequence{ "{", _table_content, "}", builder = fget(1) }

View File

@@ -1,61 +1,74 @@
--
-- MobDebug 0.40
-- Copyright Paul Kulchenko 2011
-- MobDebug 0.44
-- Copyright Paul Kulchenko 2011-2012
-- Based on RemDebug 1.0 (http://www.keplerproject.org/remdebug)
--
(function()
local mobdebug = {
_NAME = "mobdebug",
_COPYRIGHT = "Paul Kulchenko",
_DESCRIPTION = "Mobile Remote Debugger for the Lua programming language",
_VERSION = "0.44"
}
module("mobdebug", package.seeall)
_COPYRIGHT = "Paul Kulchenko"
_DESCRIPTION = "Mobile Remote Debugger for the Lua programming language"
_VERSION = "0.40"
local coroutine = coroutine
local error = error
local getfenv = getfenv
local loadstring = loadstring
local io = io
local os = os
local pairs = pairs
local require = require
local setmetatable = setmetatable
local string = string
local tonumber = tonumber
local mosync = mosync
-- this is a socket class that implements maConnect interface
local function socketMobileLua()
local self = {}
self.select = function() return {} end
self.connect = coroutine.wrap(function(host, port)
while true do
local connection = maConnect("socket://" .. host .. ":" .. port)
local connection = mosync.maConnect("socket://" .. host .. ":" .. port)
if connection > 0 then
local event = SysEventCreate()
local event = mosync.SysEventCreate()
while true do
maWait(0)
maGetEvent(event)
local eventType = SysEventGetType(event)
if (EVENT_TYPE_CLOSE == eventType) then maExit(0) end
if (EVENT_TYPE_CONN == eventType and
SysEventGetConnHandle(event) == connection and
SysEventGetConnOpType(event) == CONNOP_CONNECT) then
mosync.maWait(0)
mosync.maGetEvent(event)
local eventType = mosync.SysEventGetType(event)
if (mosync.EVENT_TYPE_CLOSE == eventType) then mosync.maExit(0) end
if (mosync.EVENT_TYPE_CONN == eventType and
mosync.SysEventGetConnHandle(event) == connection and
mosync.SysEventGetConnOpType(event) == mosync.CONNOP_CONNECT) then
-- result > 0 ? success : error
if not (SysEventGetConnResult(event) > 0) then connection = nil end
if not (mosync.SysEventGetConnResult(event) > 0) then connection = nil end
break
end
end
SysFree(event)
mosync.SysFree(event)
end
host, port = coroutine.yield(connection and (function ()
local self = {}
local outBuffer = SysAlloc(1000)
local inBuffer = SysAlloc(1000)
local event = SysEventCreate()
local outBuffer = mosync.SysAlloc(1000)
local inBuffer = mosync.SysAlloc(1000)
local event = mosync.SysEventCreate()
local recvBuffer = ""
function stringToBuffer(s, buffer)
local i = 0
for c in s:gmatch(".") do
i = i + 1
local b = s:byte(i)
SysBufferSetByte(buffer, i - 1, b)
mosync.SysBufferSetByte(buffer, i - 1, b)
end
return i
end
function bufferToString(buffer, len)
local s = ""
for i = 0, len - 1 do
local c = SysBufferGetByte(buffer, i)
local c = mosync.SysBufferGetByte(buffer, i)
s = s .. string.char(c)
end
return s
@@ -63,16 +76,16 @@ local function socketMobileLua()
self.send = coroutine.wrap(function(self, msg)
while true do
local numberOfBytes = stringToBuffer(msg, outBuffer)
maConnWrite(connection, outBuffer, numberOfBytes)
mosync.maConnWrite(connection, outBuffer, numberOfBytes)
local result = 0
while true do
maWait(0)
maGetEvent(event)
local eventType = SysEventGetType(event)
if (EVENT_TYPE_CLOSE == eventType) then maExit(0) end
if (EVENT_TYPE_CONN == eventType and
SysEventGetConnHandle(event) == connection and
SysEventGetConnOpType(event) == CONNOP_WRITE) then
mosync.maWait(0)
mosync.maGetEvent(event)
local eventType = mosync.SysEventGetType(event)
if (mosync.EVENT_TYPE_CLOSE == eventType) then mosync.maExit(0) end
if (mosync.EVENT_TYPE_CONN == eventType and
mosync.SysEventGetConnHandle(event) == connection and
mosync.SysEventGetConnOpType(event) == mosync.CONNOP_WRITE) then
break
end
end
@@ -84,16 +97,16 @@ local function socketMobileLua()
local line = recvBuffer
while (len and string.len(line) < len) -- either we need len bytes
or (not len and not line:find("\n")) do -- or one line (if no len specified)
maConnRead(connection, inBuffer, 1000)
mosync.maConnRead(connection, inBuffer, 1000)
while true do
maWait(0)
maGetEvent(event)
local eventType = SysEventGetType(event)
if (EVENT_TYPE_CLOSE == eventType) then maExit(0) end
if (EVENT_TYPE_CONN == eventType and
SysEventGetConnHandle(event) == connection and
SysEventGetConnOpType(event) == CONNOP_READ) then
local result = SysEventGetConnResult(event);
mosync.maWait(0)
mosync.maGetEvent(event)
local eventType = mosync.SysEventGetType(event)
if (mosync.EVENT_TYPE_CLOSE == eventType) then mosync.maExit(0) end
if (mosync.EVENT_TYPE_CONN == eventType and
mosync.SysEventGetConnHandle(event) == connection and
mosync.SysEventGetConnOpType(event) == mosync.CONNOP_READ) then
local result = mosync.SysEventGetConnResult(event);
if result > 0 then line = line .. bufferToString(inBuffer, result) end
break; -- got the event we wanted; now check if we have all we need
end
@@ -112,10 +125,10 @@ local function socketMobileLua()
end)
self.close = coroutine.wrap(function(self)
while true do
SysFree(inBuffer)
SysFree(outBuffer)
SysFree(event)
maConnClose(connection)
mosync.SysFree(inBuffer)
mosync.SysFree(outBuffer)
mosync.SysFree(event)
mosync.maConnClose(connection)
coroutine.yield(self)
end
end)
@@ -127,7 +140,7 @@ local function socketMobileLua()
return self
end
local socket = maConnect and socketMobileLua() or (require "socket")
local socket = mosync and socketMobileLua() or (require "socket")
--
-- RemDebug 1.0 Beta
@@ -139,7 +152,11 @@ local coro_debugger
local events = { BREAK = 1, WATCH = 2 }
local breakpoints = {}
local watches = {}
local abort = false
local lastsource
local lastfile
local watchescnt = 0
local abort -- default value is nil; this is used in start/loop distinction
local check_break = false
local step_into = false
local step_over = false
local step_level = 0
@@ -147,12 +164,12 @@ local stack_level = 0
local server
local debugee = function ()
local a = 1
print("Dummy script for debugging 1")
print("Dummy script for debugging 2")
a = a + 1
return "ok"
end
local function set_breakpoint(file, line)
if file == '-' and lastfile then file = lastfile end
if not breakpoints[file] then
breakpoints[file] = {}
end
@@ -160,6 +177,7 @@ local function set_breakpoint(file, line)
end
local function remove_breakpoint(file, line)
if file == '-' and lastfile then file = lastfile end
if breakpoints[file] then
breakpoints[file][line] = nil
end
@@ -224,29 +242,40 @@ local function debug_hook(event, line)
local caller = debug.getinfo(2, "S")
-- grab the filename and fix it if needed
local file = caller.source
if string.find(file, "@") == 1 then
file = string.sub(file, 2)
end
-- remove references to the current folder (./ or .\)
if string.find(file, "./") == 1 or string.find(file, ".\\") == 1 then
file = string.sub(file, 3)
end
-- fix filenames for loaded strings that may contain scripts with newlines
if string.find(file, "\n") then
file = string.sub(string.gsub(file, "\n", ' '), 1, 32) -- limit to 32 chars
local file = lastfile
if (lastsource ~= caller.source) then
lastsource = caller.source
file = lastsource
if string.find(file, "@") == 1 then file = string.sub(file, 2) end
-- remove references to the current folder (./ or .\)
if string.find(file, "%.[/\\]") == 1 then file = string.sub(file, 3) end
-- fix filenames for loaded strings that may contain scripts with newlines
if string.find(file, "\n") then
file = string.sub(string.gsub(file, "\n", ' '), 1, 32) -- limit to 32 chars
end
file = string.gsub(file, "\\", "/") -- convert slash
lastfile = file
end
local 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)
restore_vars(vars)
local vars
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)
restore_vars(vars)
end
end
end
if step_into or (step_over and stack_level <= step_level) or has_breakpoint(file, line) then
if step_into
or (step_over and stack_level <= step_level)
or has_breakpoint(file, line)
or (check_break and (socket.select({server}, {}, 0))[server]) then
vars = vars or capture_vars()
check_break = true -- this is only needed to avoid breaking too early when debugging is starting
step_into = false
step_over = false
coroutine.resume(coro_debugger, events.BREAK, vars, file, line)
@@ -254,26 +283,49 @@ local function debug_hook(event, line)
end
end
local function debugger_loop()
local function debugger_loop(sfile, sline)
local command
local eval_env = {}
local function emptyWatch () return false end
while true do
local line = server:receive()
local line, err
if server.settimeout then server:settimeout(0.010) end
while true do
line, err = server:receive()
if not line and err == "timeout" then
-- yield for wx GUI applications if possible to avoid "busyness"
if wx and wx.wxGetApp then
local app = wx.wxGetApp()
local win = app:GetTopWindow()
if win then
-- process messages in a regular way
-- and exit as soon as the event loop is idle
win:Connect(wx.wxEVT_IDLE, function(event)
app:ExitMainLoop()
win:Disconnect(wx.wxID_ANY, wx.wxID_ANY, wx.wxEVT_IDLE)
end)
app:MainLoop()
end
end
else
break
end
end
if server.settimeout then server:settimeout() end -- back to blocking
command = string.sub(line, string.find(line, "^[A-Z]+"))
if command == "SETB" then
local _, _, _, filename, line = string.find(line, "^([A-Z]+)%s+([%w%p%s]+)%s+(%d+)%s*$")
if filename and line then
set_breakpoint(filename, tonumber(line))
local _, _, _, file, line = string.find(line, "^([A-Z]+)%s+([%w%p%s]+)%s+(%d+)%s*$")
if file and line then
set_breakpoint(file, tonumber(line))
server:send("200 OK\n")
else
server:send("400 Bad Request\n")
end
elseif command == "DELB" then
local _, _, _, filename, line = string.find(line, "^([A-Z]+)%s+([%w%p%s]+)%s+(%d+)%s*$")
if filename and line then
remove_breakpoint(filename, tonumber(line))
_, _, _, file, line = string.find(line, "^([A-Z]+)%s+([%w%p%s]+)%s+(%d+)%s*$")
if file and line then
remove_breakpoint(file, tonumber(line))
server:send("200 OK\n")
else
server:send("400 Bad Request\n")
@@ -301,32 +353,43 @@ local function debugger_loop()
elseif command == "LOAD" then
local _, _, size, name = string.find(line, "^[A-Z]+%s+(%d+)%s+([%w%p%s]*[%w%p]+)%s*$")
size = tonumber(size)
if size == 0 then -- RELOAD the current script being debugged
server:send("200 OK 0\n")
abort = true
coroutine.yield() -- this should not return as the hook will abort
end
local chunk = server:receive(size)
if chunk then -- LOAD a new script for debugging
local func, res = loadstring(chunk, name)
if func then
server:send("200 OK 0\n")
debugee = func
abort = true
coroutine.yield() -- this should not return as the hook will abort
if abort == nil then -- no LOAD/RELOAD allowed inside start()
if size > 0 then local _ = server:receive(size) end
if sfile and sline then
server:send("201 Started " .. sfile .. " " .. sline .. "\n")
else
server:send("401 Error in Expression " .. string.len(res) .. "\n")
server:send(res)
server:send("200 OK 0\n")
end
else
server:send("400 Bad Request\n")
if size == 0 then -- RELOAD the current script being debugged
server:send("200 OK 0\n")
abort = true
coroutine.yield() -- this should not return as the hook will abort
end
local chunk = server:receive(size)
if chunk then -- LOAD a new script for debugging
local func, res = loadstring(chunk, name)
if func then
server:send("200 OK 0\n")
debugee = func
abort = true
coroutine.yield() -- this should not return as the hook will abort
else
server:send("401 Error in Expression " .. string.len(res) .. "\n")
server:send(res)
end
else
server:send("400 Bad Request\n")
end
end
elseif command == "SETW" then
local _, _, exp = string.find(line, "^[A-Z]+%s+(.+)%s*$")
if exp then
local func = loadstring("return(" .. exp .. ")")
if func then
watchescnt = watchescnt + 1
local newidx = #watches + 1
watches[newidx] = func
server:send("200 OK " .. newidx .. "\n")
@@ -340,13 +403,15 @@ local function debugger_loop()
local _, _, index = string.find(line, "^[A-Z]+%s+(%d+)%s*$")
index = tonumber(index)
if index > 0 and index <= #watches then
watchescnt = watchescnt - (watches[index] ~= emptyWatch and 1 or 0)
watches[index] = emptyWatch
server:send("200 OK\n")
server:send("200 OK\n")
else
server:send("400 Bad Request\n")
end
elseif command == "RUN" then
server:send("200 OK\n")
local ev, vars, file, line, idx_watch = coroutine.yield()
eval_env = vars
if ev == events.BREAK then
@@ -360,6 +425,7 @@ local function debugger_loop()
elseif command == "STEP" then
server:send("200 OK\n")
step_into = true
local ev, vars, file, line, idx_watch = coroutine.yield()
eval_env = vars
if ev == events.BREAK then
@@ -398,28 +464,30 @@ local function debugger_loop()
end
end
function connect(controller_host, controller_port)
local function connect(controller_host, controller_port)
return socket.connect(controller_host, controller_port)
end
-- Tries to start the debug session by connecting with a controller
function start(controller_host, controller_port)
local function start(controller_host, controller_port)
server = socket.connect(controller_host, controller_port)
if server then
print("Connected to " .. controller_host .. ":" .. controller_port)
local info = debug.getinfo(2, "Sl")
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
debug.sethook(debug_hook, "lcr")
coro_debugger = coroutine.create(debugger_loop)
return coroutine.resume(coro_debugger)
return coroutine.resume(coro_debugger, file, info.currentline)
else
print("Could not connect to " .. controller_host .. ":" .. controller_port)
end
end
function loop(controller_host, controller_port)
local function loop(controller_host, controller_port)
server = socket.connect(controller_host, controller_port)
if server then
print("Connected to " .. controller_host .. ":" .. controller_port)
local function report(trace, err)
local msg = err .. "\n" .. trace
server:send("401 Error in Execution " .. string.len(msg) .. "\n")
@@ -456,7 +524,7 @@ end
local basedir = ""
-- Handles server debugging commands
function handle(params, client)
local function handle(params, client)
local _, _, command = string.find(params, "^([a-z]+)")
local file, line, watch_idx
if command == "run" or command == "step" or command == "out"
@@ -494,13 +562,14 @@ function handle(params, client)
return nil, nil, "Unknown error" -- use return here for those cases where os.exit() is not wanted
end
elseif command == "setb" then
_, _, _, filename, line = string.find(params, "^([a-z]+)%s+([%w%p%s]+)%s+(%d+)%s*$")
if filename and line then
filename = string.gsub(filename, basedir, '') -- remove basedir
if not breakpoints[filename] then breakpoints[filename] = {} end
client:send("SETB " .. filename .. " " .. line .. "\n")
_, _, _, file, line = string.find(params, "^([a-z]+)%s+([%w%p%s]+)%s+(%d+)%s*$")
if file and line then
file = string.gsub(file, "\\", "/") -- convert slash
file = string.gsub(file, basedir, '') -- remove basedir
if not breakpoints[file] then breakpoints[file] = {} end
client:send("SETB " .. file .. " " .. line .. "\n")
if client:receive() == "200 OK" then
breakpoints[filename][line] = true
breakpoints[file][line] = true
else
print("Error: breakpoint not inserted")
end
@@ -523,13 +592,14 @@ function handle(params, client)
print("Invalid command")
end
elseif command == "delb" then
_, _, _, filename, line = string.find(params, "^([a-z]+)%s+([%w%p%s]+)%s+(%d+)%s*$")
if filename and line then
filename = string.gsub(filename, basedir, '') -- remove basedir
if not breakpoints[filename] then breakpoints[filename] = {} end
client:send("DELB " .. filename .. " " .. line .. "\n")
_, _, _, file, line = string.find(params, "^([a-z]+)%s+([%w%p%s]+)%s+(%d+)%s*$")
if file and line then
file = string.gsub(file, "\\", "/") -- convert slash
file = string.gsub(file, basedir, '') -- remove basedir
if not breakpoints[file] then breakpoints[file] = {} end
client:send("DELB " .. file .. " " .. line .. "\n")
if client:receive() == "200 OK" then
breakpoints[filename][line] = nil
breakpoints[file][line] = nil
else
print("Error: breakpoint not removed")
end
@@ -537,13 +607,13 @@ function handle(params, client)
print("Invalid command")
end
elseif command == "delallb" then
for filename, breaks in pairs(breakpoints) do
for file, breaks in pairs(breakpoints) do
for line, _ in pairs(breaks) do
client:send("DELB " .. filename .. " " .. line .. "\n")
client:send("DELB " .. file .. " " .. line .. "\n")
if client:receive() == "200 OK" then
breakpoints[filename][line] = nil
breakpoints[file][line] = nil
else
print("Error: breakpoint at file " .. filename .. " line " .. line .. " not removed")
print("Error: breakpoint at file " .. file .. " line " .. line .. " not removed")
end
end
end
@@ -573,8 +643,10 @@ function handle(params, client)
local _, _, exp = string.find(params, "^[a-z]+%s+(.+)$")
if exp or (command == "reload") then
if command == "eval" then
client:send("EXEC return (" .. exp .. ")\n")
exp = string.gsub(exp, "\n", " ") -- convert new lines
client:send("EXEC return " .. exp .. "\n")
elseif command == "exec" then
exp = string.gsub(exp, "\n", " ") -- convert new lines
client:send("EXEC " .. exp .. "\n")
elseif command == "reload" then
client:send("LOAD 0 -\n")
@@ -584,12 +656,13 @@ function handle(params, client)
local lines = file:read("*all")
file:close()
local filename = string.gsub(exp, basedir, '') -- remove basedir
client:send("LOAD " .. string.len(lines) .. " " .. filename .. "\n")
local file = string.gsub(exp, "\\", "/") -- convert slash
file = string.gsub(file, basedir, '') -- remove basedir
client:send("LOAD " .. string.len(lines) .. " " .. file .. "\n")
client:send(lines)
end
local line = client:receive()
local _, _, status, len = string.find(line, "^(%d+)[%s%w]+%s+(%d+)%s*$")
local params = client:receive()
local _, _, status, len = string.find(params, "^(%d+)[%w%p%s]+%s+(%d+)%s*$")
if status == "200" then
len = tonumber(len)
if len > 0 then
@@ -597,6 +670,8 @@ function handle(params, client)
print(res)
return res
end
elseif status == "201" then
_, _, file, line = string.find(params, "^201 Started%s+([%w%p%s]+)%s+(%d+)%s*$")
elseif status == "401" then
len = tonumber(len)
local res = client:receive(len)
@@ -624,6 +699,7 @@ function handle(params, client)
elseif command == "basedir" then
local _, _, dir = string.find(params, "^[a-z]+%s+(.+)$")
if dir then
dir = string.gsub(dir, "\\", "/") -- convert slash
if not string.find(dir, "/$") then dir = dir .. "/" end
basedir = dir
print("New base directory is " .. basedir)
@@ -660,7 +736,7 @@ function handle(params, client)
end
-- Starts debugging server
function listen(host, port)
local function listen(host, port)
local socket = require "socket"
@@ -693,4 +769,15 @@ function listen(host, port)
end
end
end)()
-- make public functions available
mobdebug.listen = listen
mobdebug.loop = loop
mobdebug.handle = handle
mobdebug.connect = connect
mobdebug.start = start
-- this is needed to make "require 'modebug'" to work when mobdebug
-- module is loaded manually
package.loaded.mobdebug = mobdebug
return mobdebug

View File

@@ -1,291 +1,291 @@
-----------------------------------------------------------------------------
-- LTN12 - Filters, sources, sinks and pumps.
-- LuaSocket toolkit.
-- Author: Diego Nehab
-- RCS ID: $Id: ltn12.lua 1418 2006-04-25 09:38:15Z 3rdparty $
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
-- Declare module
-----------------------------------------------------------------------------
local string = require("string")
local table = require("table")
local base = _G
module("ltn12")
filter = {}
source = {}
sink = {}
pump = {}
-- 2048 seems to be better in windows...
BLOCKSIZE = 2048
-----------------------------------------------------------------------------
-- Filter stuff
-----------------------------------------------------------------------------
-- returns a high level filter that cycles a low-level filter
function filter.cycle(low, ctx, extra)
base.assert(low)
return function(chunk)
local ret
ret, ctx = low(ctx, chunk, extra)
return ret
end
end
-- chains a bunch of filters together
-- (thanks to Wim Couwenberg)
function filter.chain(...)
local n = table.getn(arg)
local top, index = 1, 1
local retry = ""
return function(chunk)
retry = chunk and retry
while true do
if index == top then
chunk = arg[index](chunk)
if chunk == "" or top == n then return chunk
elseif chunk then index = index + 1
else
top = top+1
index = top
end
else
chunk = arg[index](chunk or "")
if chunk == "" then
index = index - 1
chunk = retry
elseif chunk then
if index == n then return chunk
else index = index + 1 end
else base.error("filter returned inappropriate nil") end
end
end
end
end
-----------------------------------------------------------------------------
-- Source stuff
-----------------------------------------------------------------------------
-- create an empty source
local function empty()
return nil
end
function source.empty()
return empty
end
-- returns a source that just outputs an error
function source.error(err)
return function()
return nil, err
end
end
-- creates a file source
function source.file(handle, io_err)
if handle then
return function()
local chunk = handle:read(BLOCKSIZE)
if not chunk then handle:close() end
return chunk
end
else return source.error(io_err or "unable to open file") end
end
-- turns a fancy source into a simple source
function source.simplify(src)
base.assert(src)
return function()
local chunk, err_or_new = src()
src = err_or_new or src
if not chunk then return nil, err_or_new
else return chunk end
end
end
-- creates string source
function source.string(s)
if s then
local i = 1
return function()
local chunk = string.sub(s, i, i+BLOCKSIZE-1)
i = i + BLOCKSIZE
if chunk ~= "" then return chunk
else return nil end
end
else return source.empty() end
end
-- creates rewindable source
function source.rewind(src)
base.assert(src)
local t = {}
return function(chunk)
if not chunk then
chunk = table.remove(t)
if not chunk then return src()
else return chunk end
else
table.insert(t, chunk)
end
end
end
function source.chain(src, f)
base.assert(src and f)
local last_in, last_out = "", ""
local state = "feeding"
local err
return function()
if not last_out then
base.error('source is empty!', 2)
end
while true do
if state == "feeding" then
last_in, err = src()
if err then return nil, err end
last_out = f(last_in)
if not last_out then
if last_in then
base.error('filter returned inappropriate nil')
else
return nil
end
elseif last_out ~= "" then
state = "eating"
if last_in then last_in = "" end
return last_out
end
else
last_out = f(last_in)
if last_out == "" then
if last_in == "" then
state = "feeding"
else
base.error('filter returned ""')
end
elseif not last_out then
if last_in then
base.error('filter returned inappropriate nil')
else
return nil
end
else
return last_out
end
end
end
end
end
-- creates a source that produces contents of several sources, one after the
-- other, as if they were concatenated
-- (thanks to Wim Couwenberg)
function source.cat(...)
local src = table.remove(arg, 1)
return function()
while src do
local chunk, err = src()
if chunk then return chunk end
if err then return nil, err end
src = table.remove(arg, 1)
end
end
end
-----------------------------------------------------------------------------
-- Sink stuff
-----------------------------------------------------------------------------
-- creates a sink that stores into a table
function sink.table(t)
t = t or {}
local f = function(chunk, err)
if chunk then table.insert(t, chunk) end
return 1
end
return f, t
end
-- turns a fancy sink into a simple sink
function sink.simplify(snk)
base.assert(snk)
return function(chunk, err)
local ret, err_or_new = snk(chunk, err)
if not ret then return nil, err_or_new end
snk = err_or_new or snk
return 1
end
end
-- creates a file sink
function sink.file(handle, io_err)
if handle then
return function(chunk, err)
if not chunk then
handle:close()
return 1
else return handle:write(chunk) end
end
else return sink.error(io_err or "unable to open file") end
end
-- creates a sink that discards data
local function null()
return 1
end
function sink.null()
return null
end
-- creates a sink that just returns an error
function sink.error(err)
return function()
return nil, err
end
end
-- chains a sink with a filter
function sink.chain(f, snk)
base.assert(f and snk)
return function(chunk, err)
if chunk ~= "" then
local filtered = f(chunk)
local done = chunk and ""
while true do
local ret, snkerr = snk(filtered, err)
if not ret then return nil, snkerr end
if filtered == done then return 1 end
filtered = f(done)
end
else return 1 end
end
end
-----------------------------------------------------------------------------
-- Pump stuff
-----------------------------------------------------------------------------
-- pumps one chunk from the source to the sink
function pump.step(src, snk)
local chunk, src_err = src()
local ret, snk_err = snk(chunk, src_err)
if chunk and ret then return 1
else return nil, src_err or snk_err end
end
-- pumps all data from a source to a sink, using a step function
function pump.all(src, snk, step)
base.assert(src and snk)
step = step or pump.step
while true do
local ret, err = step(src, snk)
if not ret then
if err then return nil, err
else return 1 end
end
end
end
-----------------------------------------------------------------------------
-- LTN12 - Filters, sources, sinks and pumps.
-- LuaSocket toolkit.
-- Author: Diego Nehab
-- RCS ID: $Id: ltn12.lua 1418 2006-04-25 09:38:15Z 3rdparty $
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
-- Declare module
-----------------------------------------------------------------------------
local string = require("string")
local table = require("table")
local base = _G
module("ltn12")
filter = {}
source = {}
sink = {}
pump = {}
-- 2048 seems to be better in windows...
BLOCKSIZE = 2048
-----------------------------------------------------------------------------
-- Filter stuff
-----------------------------------------------------------------------------
-- returns a high level filter that cycles a low-level filter
function filter.cycle(low, ctx, extra)
base.assert(low)
return function(chunk)
local ret
ret, ctx = low(ctx, chunk, extra)
return ret
end
end
-- chains a bunch of filters together
-- (thanks to Wim Couwenberg)
function filter.chain(...)
local n = table.getn(arg)
local top, index = 1, 1
local retry = ""
return function(chunk)
retry = chunk and retry
while true do
if index == top then
chunk = arg[index](chunk)
if chunk == "" or top == n then return chunk
elseif chunk then index = index + 1
else
top = top+1
index = top
end
else
chunk = arg[index](chunk or "")
if chunk == "" then
index = index - 1
chunk = retry
elseif chunk then
if index == n then return chunk
else index = index + 1 end
else base.error("filter returned inappropriate nil") end
end
end
end
end
-----------------------------------------------------------------------------
-- Source stuff
-----------------------------------------------------------------------------
-- create an empty source
local function empty()
return nil
end
function source.empty()
return empty
end
-- returns a source that just outputs an error
function source.error(err)
return function()
return nil, err
end
end
-- creates a file source
function source.file(handle, io_err)
if handle then
return function()
local chunk = handle:read(BLOCKSIZE)
if not chunk then handle:close() end
return chunk
end
else return source.error(io_err or "unable to open file") end
end
-- turns a fancy source into a simple source
function source.simplify(src)
base.assert(src)
return function()
local chunk, err_or_new = src()
src = err_or_new or src
if not chunk then return nil, err_or_new
else return chunk end
end
end
-- creates string source
function source.string(s)
if s then
local i = 1
return function()
local chunk = string.sub(s, i, i+BLOCKSIZE-1)
i = i + BLOCKSIZE
if chunk ~= "" then return chunk
else return nil end
end
else return source.empty() end
end
-- creates rewindable source
function source.rewind(src)
base.assert(src)
local t = {}
return function(chunk)
if not chunk then
chunk = table.remove(t)
if not chunk then return src()
else return chunk end
else
table.insert(t, chunk)
end
end
end
function source.chain(src, f)
base.assert(src and f)
local last_in, last_out = "", ""
local state = "feeding"
local err
return function()
if not last_out then
base.error('source is empty!', 2)
end
while true do
if state == "feeding" then
last_in, err = src()
if err then return nil, err end
last_out = f(last_in)
if not last_out then
if last_in then
base.error('filter returned inappropriate nil')
else
return nil
end
elseif last_out ~= "" then
state = "eating"
if last_in then last_in = "" end
return last_out
end
else
last_out = f(last_in)
if last_out == "" then
if last_in == "" then
state = "feeding"
else
base.error('filter returned ""')
end
elseif not last_out then
if last_in then
base.error('filter returned inappropriate nil')
else
return nil
end
else
return last_out
end
end
end
end
end
-- creates a source that produces contents of several sources, one after the
-- other, as if they were concatenated
-- (thanks to Wim Couwenberg)
function source.cat(...)
local src = table.remove(arg, 1)
return function()
while src do
local chunk, err = src()
if chunk then return chunk end
if err then return nil, err end
src = table.remove(arg, 1)
end
end
end
-----------------------------------------------------------------------------
-- Sink stuff
-----------------------------------------------------------------------------
-- creates a sink that stores into a table
function sink.table(t)
t = t or {}
local f = function(chunk, err)
if chunk then table.insert(t, chunk) end
return 1
end
return f, t
end
-- turns a fancy sink into a simple sink
function sink.simplify(snk)
base.assert(snk)
return function(chunk, err)
local ret, err_or_new = snk(chunk, err)
if not ret then return nil, err_or_new end
snk = err_or_new or snk
return 1
end
end
-- creates a file sink
function sink.file(handle, io_err)
if handle then
return function(chunk, err)
if not chunk then
handle:close()
return 1
else return handle:write(chunk) end
end
else return sink.error(io_err or "unable to open file") end
end
-- creates a sink that discards data
local function null()
return 1
end
function sink.null()
return null
end
-- creates a sink that just returns an error
function sink.error(err)
return function()
return nil, err
end
end
-- chains a sink with a filter
function sink.chain(f, snk)
base.assert(f and snk)
return function(chunk, err)
if chunk ~= "" then
local filtered = f(chunk)
local done = chunk and ""
while true do
local ret, snkerr = snk(filtered, err)
if not ret then return nil, snkerr end
if filtered == done then return 1 end
filtered = f(done)
end
else return 1 end
end
end
-----------------------------------------------------------------------------
-- Pump stuff
-----------------------------------------------------------------------------
-- pumps one chunk from the source to the sink
function pump.step(src, snk)
local chunk, src_err = src()
local ret, snk_err = snk(chunk, src_err)
if chunk and ret then return 1
else return nil, src_err or snk_err end
end
-- pumps all data from a source to a sink, using a step function
function pump.all(src, snk, step)
base.assert(src and snk)
step = step or pump.step
while true do
local ret, err = step(src, snk)
if not ret then
if err then return nil, err
else return 1 end
end
end
end

View File

@@ -1,86 +1,86 @@
-----------------------------------------------------------------------------
-- MIME support for the Lua language.
-- Author: Diego Nehab
-- Conforming to RFCs 2045-2049
-- RCS ID: $Id: mime.lua 1418 2006-04-25 09:38:15Z 3rdparty $
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
-- Declare module and import dependencies
-----------------------------------------------------------------------------
local base = _G
local ltn12 = require("ltn12")
local mime = require("mime.core")
local io = require("io")
local string = require("string")
module("mime")
-- encode, decode and wrap algorithm tables
encodet = {}
decodet = {}
wrapt = {}
-- creates a function that chooses a filter by name from a given table
local function choose(table)
return function(name, opt1, opt2)
if base.type(name) ~= "string" then
name, opt1, opt2 = "default", name, opt1
end
local f = table[name or "nil"]
if not f then error("unknown key (" .. base.tostring(name) .. ")", 3)
else return f(opt1, opt2) end
end
end
-- define the encoding filters
encodet['base64'] = function()
return ltn12.filter.cycle(b64, "")
end
encodet['quoted-printable'] = function(mode)
return ltn12.filter.cycle(qp, "",
(mode == "binary") and "=0D=0A" or "\r\n")
end
-- define the decoding filters
decodet['base64'] = function()
return ltn12.filter.cycle(unb64, "")
end
decodet['quoted-printable'] = function()
return ltn12.filter.cycle(unqp, "")
end
local function format(chunk)
if chunk then
if chunk == "" then return "''"
else return string.len(chunk) end
else return "nil" end
end
-- define the line-wrap filters
wrapt['text'] = function(length)
length = length or 76
return ltn12.filter.cycle(wrp, length, length)
end
wrapt['base64'] = wrapt['text']
wrapt['default'] = wrapt['text']
wrapt['quoted-printable'] = function()
return ltn12.filter.cycle(qpwrp, 76, 76)
end
-- function that choose the encoding, decoding or wrap algorithm
encode = choose(encodet)
decode = choose(decodet)
wrap = choose(wrapt)
-- define the end-of-line normalization filter
function normalize(marker)
return ltn12.filter.cycle(eol, 0, marker)
end
-- high level stuffing filter
function stuff()
return ltn12.filter.cycle(dot, 2)
end
-----------------------------------------------------------------------------
-- MIME support for the Lua language.
-- Author: Diego Nehab
-- Conforming to RFCs 2045-2049
-- RCS ID: $Id: mime.lua 1418 2006-04-25 09:38:15Z 3rdparty $
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
-- Declare module and import dependencies
-----------------------------------------------------------------------------
local base = _G
local ltn12 = require("ltn12")
local mime = require("mime.core")
local io = require("io")
local string = require("string")
module("mime")
-- encode, decode and wrap algorithm tables
encodet = {}
decodet = {}
wrapt = {}
-- creates a function that chooses a filter by name from a given table
local function choose(table)
return function(name, opt1, opt2)
if base.type(name) ~= "string" then
name, opt1, opt2 = "default", name, opt1
end
local f = table[name or "nil"]
if not f then error("unknown key (" .. base.tostring(name) .. ")", 3)
else return f(opt1, opt2) end
end
end
-- define the encoding filters
encodet['base64'] = function()
return ltn12.filter.cycle(b64, "")
end
encodet['quoted-printable'] = function(mode)
return ltn12.filter.cycle(qp, "",
(mode == "binary") and "=0D=0A" or "\r\n")
end
-- define the decoding filters
decodet['base64'] = function()
return ltn12.filter.cycle(unb64, "")
end
decodet['quoted-printable'] = function()
return ltn12.filter.cycle(unqp, "")
end
local function format(chunk)
if chunk then
if chunk == "" then return "''"
else return string.len(chunk) end
else return "nil" end
end
-- define the line-wrap filters
wrapt['text'] = function(length)
length = length or 76
return ltn12.filter.cycle(wrp, length, length)
end
wrapt['base64'] = wrapt['text']
wrapt['default'] = wrapt['text']
wrapt['quoted-printable'] = function()
return ltn12.filter.cycle(qpwrp, 76, 76)
end
-- function that choose the encoding, decoding or wrap algorithm
encode = choose(encodet)
decode = choose(decodet)
wrap = choose(wrapt)
-- define the end-of-line normalization filter
function normalize(marker)
return ltn12.filter.cycle(eol, 0, marker)
end
-- high level stuffing filter
function stuff()
return ltn12.filter.cycle(dot, 2)
end

View File

@@ -1,133 +1,133 @@
-----------------------------------------------------------------------------
-- LuaSocket helper module
-- Author: Diego Nehab
-- RCS ID: $Id: socket.lua 1418 2006-04-25 09:38:15Z 3rdparty $
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
-- Declare module and import dependencies
-----------------------------------------------------------------------------
local base = _G
local string = require("string")
local math = require("math")
local socket = require("socket.core")
module("socket")
-----------------------------------------------------------------------------
-- Exported auxiliar functions
-----------------------------------------------------------------------------
function connect(address, port, laddress, lport)
local sock, err = socket.tcp()
if not sock then return nil, err end
if laddress then
local res, err = sock:bind(laddress, lport, -1)
if not res then return nil, err end
end
local res, err = sock:connect(address, port)
if not res then return nil, err end
return sock
end
function bind(host, port, backlog)
local sock, err = socket.tcp()
if not sock then return nil, err end
sock:setoption("reuseaddr", true)
local res, err = sock:bind(host, port)
if not res then return nil, err end
res, err = sock:listen(backlog)
if not res then return nil, err end
return sock
end
try = newtry()
function choose(table)
return function(name, opt1, opt2)
if base.type(name) ~= "string" then
name, opt1, opt2 = "default", name, opt1
end
local f = table[name or "nil"]
if not f then base.error("unknown key (".. base.tostring(name) ..")", 3)
else return f(opt1, opt2) end
end
end
-----------------------------------------------------------------------------
-- Socket sources and sinks, conforming to LTN12
-----------------------------------------------------------------------------
-- create namespaces inside LuaSocket namespace
sourcet = {}
sinkt = {}
BLOCKSIZE = 2048
sinkt["close-when-done"] = function(sock)
return base.setmetatable({
getfd = function() return sock:getfd() end,
dirty = function() return sock:dirty() end
}, {
__call = function(self, chunk, err)
if not chunk then
sock:close()
return 1
else return sock:send(chunk) end
end
})
end
sinkt["keep-open"] = function(sock)
return base.setmetatable({
getfd = function() return sock:getfd() end,
dirty = function() return sock:dirty() end
}, {
__call = function(self, chunk, err)
if chunk then return sock:send(chunk)
else return 1 end
end
})
end
sinkt["default"] = sinkt["keep-open"]
sink = choose(sinkt)
sourcet["by-length"] = function(sock, length)
return base.setmetatable({
getfd = function() return sock:getfd() end,
dirty = function() return sock:dirty() end
}, {
__call = function()
if length <= 0 then return nil end
local size = math.min(socket.BLOCKSIZE, length)
local chunk, err = sock:receive(size)
if err then return nil, err end
length = length - string.len(chunk)
return chunk
end
})
end
sourcet["until-closed"] = function(sock)
local done
return base.setmetatable({
getfd = function() return sock:getfd() end,
dirty = function() return sock:dirty() end
}, {
__call = function()
if done then return nil end
local chunk, err, partial = sock:receive(socket.BLOCKSIZE)
if not err then return chunk
elseif err == "closed" then
sock:close()
done = 1
return partial
else return nil, err end
end
})
end
sourcet["default"] = sourcet["until-closed"]
source = choose(sourcet)
-----------------------------------------------------------------------------
-- LuaSocket helper module
-- Author: Diego Nehab
-- RCS ID: $Id: socket.lua 1418 2006-04-25 09:38:15Z 3rdparty $
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
-- Declare module and import dependencies
-----------------------------------------------------------------------------
local base = _G
local string = require("string")
local math = require("math")
local socket = require("socket.core")
module("socket")
-----------------------------------------------------------------------------
-- Exported auxiliar functions
-----------------------------------------------------------------------------
function connect(address, port, laddress, lport)
local sock, err = socket.tcp()
if not sock then return nil, err end
if laddress then
local res, err = sock:bind(laddress, lport, -1)
if not res then return nil, err end
end
local res, err = sock:connect(address, port)
if not res then return nil, err end
return sock
end
function bind(host, port, backlog)
local sock, err = socket.tcp()
if not sock then return nil, err end
sock:setoption("reuseaddr", true)
local res, err = sock:bind(host, port)
if not res then return nil, err end
res, err = sock:listen(backlog)
if not res then return nil, err end
return sock
end
try = newtry()
function choose(table)
return function(name, opt1, opt2)
if base.type(name) ~= "string" then
name, opt1, opt2 = "default", name, opt1
end
local f = table[name or "nil"]
if not f then base.error("unknown key (".. base.tostring(name) ..")", 3)
else return f(opt1, opt2) end
end
end
-----------------------------------------------------------------------------
-- Socket sources and sinks, conforming to LTN12
-----------------------------------------------------------------------------
-- create namespaces inside LuaSocket namespace
sourcet = {}
sinkt = {}
BLOCKSIZE = 2048
sinkt["close-when-done"] = function(sock)
return base.setmetatable({
getfd = function() return sock:getfd() end,
dirty = function() return sock:dirty() end
}, {
__call = function(self, chunk, err)
if not chunk then
sock:close()
return 1
else return sock:send(chunk) end
end
})
end
sinkt["keep-open"] = function(sock)
return base.setmetatable({
getfd = function() return sock:getfd() end,
dirty = function() return sock:dirty() end
}, {
__call = function(self, chunk, err)
if chunk then return sock:send(chunk)
else return 1 end
end
})
end
sinkt["default"] = sinkt["keep-open"]
sink = choose(sinkt)
sourcet["by-length"] = function(sock, length)
return base.setmetatable({
getfd = function() return sock:getfd() end,
dirty = function() return sock:dirty() end
}, {
__call = function()
if length <= 0 then return nil end
local size = math.min(socket.BLOCKSIZE, length)
local chunk, err = sock:receive(size)
if err then return nil, err end
length = length - string.len(chunk)
return chunk
end
})
end
sourcet["until-closed"] = function(sock)
local done
return base.setmetatable({
getfd = function() return sock:getfd() end,
dirty = function() return sock:dirty() end
}, {
__call = function()
if done then return nil end
local chunk, err, partial = sock:receive(socket.BLOCKSIZE)
if not err then return chunk
elseif err == "closed" then
sock:close()
done = 1
return partial
else return nil, err end
end
})
end
sourcet["default"] = sourcet["until-closed"]
source = choose(sourcet)

View File

@@ -1,280 +1,280 @@
-----------------------------------------------------------------------------
-- FTP support for the Lua language
-- LuaSocket toolkit.
-- Author: Diego Nehab
-- RCS ID: $Id: ftp.lua 1418 2006-04-25 09:38:15Z 3rdparty $
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
-- Declare module and import dependencies
-----------------------------------------------------------------------------
local base = _G
local table = require("table")
local string = require("string")
local math = require("math")
local socket = require("socket")
local url = require("socket.url")
local tp = require("socket.tp")
local ltn12 = require("ltn12")
module("socket.ftp")
-----------------------------------------------------------------------------
-- Program constants
-----------------------------------------------------------------------------
-- timeout in seconds before the program gives up on a connection
TIMEOUT = 60
-- default port for ftp service
PORT = 21
-- this is the default anonymous password. used when no password is
-- provided in url. should be changed to your e-mail.
USER = "ftp"
PASSWORD = "anonymous@anonymous.org"
-----------------------------------------------------------------------------
-- Low level FTP API
-----------------------------------------------------------------------------
local metat = { __index = {} }
function open(server, port, create)
local tp = socket.try(tp.connect(server, port or PORT, create, TIMEOUT))
local f = base.setmetatable({ tp = tp }, metat)
-- make sure everything gets closed in an exception
f.try = socket.newtry(function() f:close() end)
return f
end
function metat.__index:portconnect()
self.try(self.server:settimeout(TIMEOUT))
self.data = self.try(self.server:accept())
self.try(self.data:settimeout(TIMEOUT))
end
function metat.__index:pasvconnect()
self.data = self.try(socket.tcp())
self.try(self.data:settimeout(TIMEOUT))
self.try(self.data:connect(self.pasvt.ip, self.pasvt.port))
end
function metat.__index:login(user, password)
self.try(self.tp:command("user", user or USER))
local code, reply = self.try(self.tp:check{"2..", 331})
if code == 331 then
self.try(self.tp:command("pass", password or PASSWORD))
self.try(self.tp:check("2.."))
end
return 1
end
function metat.__index:pasv()
self.try(self.tp:command("pasv"))
local code, reply = self.try(self.tp:check("2.."))
local pattern = "(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)"
local a, b, c, d, p1, p2 = socket.skip(2, string.find(reply, pattern))
self.try(a and b and c and d and p1 and p2, reply)
self.pasvt = {
ip = string.format("%d.%d.%d.%d", a, b, c, d),
port = p1*256 + p2
}
if self.server then
self.server:close()
self.server = nil
end
return self.pasvt.ip, self.pasvt.port
end
function metat.__index:port(ip, port)
self.pasvt = nil
if not ip then
ip, port = self.try(self.tp:getcontrol():getsockname())
self.server = self.try(socket.bind(ip, 0))
ip, port = self.try(self.server:getsockname())
self.try(server:settimeout(TIMEOUT))
end
local pl = math.mod(port, 256)
local ph = (port - pl)/256
local arg = string.gsub(string.format("%s,%d,%d", ip, ph, pl), "%.", ",")
self.try(self.tp:command("port", arg))
self.try(self.tp:check("2.."))
return 1
end
function metat.__index:send(sendt)
self.try(self.pasvt or self.server, "need port or pasv first")
-- if there is a pasvt table, we already sent a PASV command
-- we just get the data connection into self.data
if self.pasvt then self:pasvconnect() end
-- get the transfer argument and command
local argument = sendt.argument or
url.unescape(string.gsub(sendt.path or "", "^[/\\]", ""))
if argument == "" then argument = nil end
local command = sendt.command or "stor"
-- send the transfer command and check the reply
self.try(self.tp:command(command, argument))
local code, reply = self.try(self.tp:check{"2..", "1.."})
-- if there is not a a pasvt table, then there is a server
-- and we already sent a PORT command
if not self.pasvt then self:portconnect() end
-- get the sink, source and step for the transfer
local step = sendt.step or ltn12.pump.step
local checkstep = function(src, snk)
-- check status in control connection while downloading
local readyt = socket.select(readt, nil, 0)
if readyt[tp] then self.try(self.tp:check("2..")) end
return step(src, snk)
end
local sink = socket.sink("close-when-done", self.data)
-- transfer all data and check error
self.try(ltn12.pump.all(sendt.source, sink, checkstep))
if string.find(code, "1..") then self.try(self.tp:check("2..")) end
-- done with data connection
self.data:close()
-- find out how many bytes were sent
local sent = socket.skip(1, self.data:getstats())
self.data = nil
return sent
end
function metat.__index:receive(recvt)
self.try(self.pasvt or self.server, "need port or pasv first")
if self.pasvt then self:pasvconnect() end
local argument = recvt.argument or
url.unescape(string.gsub(recvt.path or "", "^[/\\]", ""))
if argument == "" then argument = nil end
local command = recvt.command or "retr"
self.try(self.tp:command(command, argument))
local code = self.try(self.tp:check{"1..", "2.."})
if not self.pasvt then self:portconnect() end
local source = socket.source("until-closed", self.data)
local step = recvt.step or ltn12.pump.step
self.try(ltn12.pump.all(source, recvt.sink, step))
if string.find(code, "1..") then self.try(self.tp:check("2..")) end
self.data:close()
self.data = nil
return 1
end
function metat.__index:cwd(dir)
self.try(self.tp:command("cwd", dir))
self.try(self.tp:check(250))
return 1
end
function metat.__index:type(type)
self.try(self.tp:command("type", type))
self.try(self.tp:check(200))
return 1
end
function metat.__index:greet()
local code = self.try(self.tp:check{"1..", "2.."})
if string.find(code, "1..") then self.try(self.tp:check("2..")) end
return 1
end
function metat.__index:quit()
self.try(self.tp:command("quit"))
self.try(self.tp:check("2.."))
return 1
end
function metat.__index:close()
if self.data then self.data:close() end
if self.server then self.server:close() end
return self.tp:close()
end
-----------------------------------------------------------------------------
-- High level FTP API
-----------------------------------------------------------------------------
function override(t)
if t.url then
u = url.parse(t.url)
for i,v in base.pairs(t) do
u[i] = v
end
return u
else return t end
end
local function tput(putt)
putt = override(putt)
socket.try(putt.host, "missing hostname")
local f = open(putt.host, putt.port, putt.create)
f:greet()
f:login(putt.user, putt.password)
if putt.type then f:type(putt.type) end
f:pasv()
local sent = f:send(putt)
f:quit()
f:close()
return sent
end
local default = {
path = "/",
scheme = "ftp"
}
local function parse(u)
local t = socket.try(url.parse(u, default))
socket.try(t.scheme == "ftp", "wrong scheme '" .. t.scheme .. "'")
socket.try(t.host, "missing hostname")
local pat = "^type=(.)$"
if t.params then
t.type = socket.skip(2, string.find(t.params, pat))
socket.try(t.type == "a" or t.type == "i",
"invalid type '" .. t.type .. "'")
end
return t
end
local function sput(u, body)
local putt = parse(u)
putt.source = ltn12.source.string(body)
return tput(putt)
end
put = socket.protect(function(putt, body)
if base.type(putt) == "string" then return sput(putt, body)
else return tput(putt) end
end)
local function tget(gett)
gett = override(gett)
socket.try(gett.host, "missing hostname")
local f = open(gett.host, gett.port, gett.create)
f:greet()
f:login(gett.user, gett.password)
if gett.type then f:type(gett.type) end
f:pasv()
f:receive(gett)
f:quit()
return f:close()
end
local function sget(u)
local gett = parse(u)
local t = {}
gett.sink = ltn12.sink.table(t)
tget(gett)
return table.concat(t)
end
command = socket.protect(function(cmdt)
cmdt = override(cmdt)
socket.try(cmdt.host, "missing hostname")
socket.try(cmdt.command, "missing command")
local f = open(cmdt.host, cmdt.port, cmdt.create)
f:greet()
f:login(cmdt.user, cmdt.password)
f.try(f.tp:command(cmdt.command, cmdt.argument))
if cmdt.check then f.try(f.tp:check(cmdt.check)) end
f:quit()
return f:close()
end)
get = socket.protect(function(gett)
if base.type(gett) == "string" then return sget(gett)
else return tget(gett) end
end)
-----------------------------------------------------------------------------
-- FTP support for the Lua language
-- LuaSocket toolkit.
-- Author: Diego Nehab
-- RCS ID: $Id: ftp.lua 1418 2006-04-25 09:38:15Z 3rdparty $
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
-- Declare module and import dependencies
-----------------------------------------------------------------------------
local base = _G
local table = require("table")
local string = require("string")
local math = require("math")
local socket = require("socket")
local url = require("socket.url")
local tp = require("socket.tp")
local ltn12 = require("ltn12")
module("socket.ftp")
-----------------------------------------------------------------------------
-- Program constants
-----------------------------------------------------------------------------
-- timeout in seconds before the program gives up on a connection
TIMEOUT = 60
-- default port for ftp service
PORT = 21
-- this is the default anonymous password. used when no password is
-- provided in url. should be changed to your e-mail.
USER = "ftp"
PASSWORD = "anonymous@anonymous.org"
-----------------------------------------------------------------------------
-- Low level FTP API
-----------------------------------------------------------------------------
local metat = { __index = {} }
function open(server, port, create)
local tp = socket.try(tp.connect(server, port or PORT, create, TIMEOUT))
local f = base.setmetatable({ tp = tp }, metat)
-- make sure everything gets closed in an exception
f.try = socket.newtry(function() f:close() end)
return f
end
function metat.__index:portconnect()
self.try(self.server:settimeout(TIMEOUT))
self.data = self.try(self.server:accept())
self.try(self.data:settimeout(TIMEOUT))
end
function metat.__index:pasvconnect()
self.data = self.try(socket.tcp())
self.try(self.data:settimeout(TIMEOUT))
self.try(self.data:connect(self.pasvt.ip, self.pasvt.port))
end
function metat.__index:login(user, password)
self.try(self.tp:command("user", user or USER))
local code, reply = self.try(self.tp:check{"2..", 331})
if code == 331 then
self.try(self.tp:command("pass", password or PASSWORD))
self.try(self.tp:check("2.."))
end
return 1
end
function metat.__index:pasv()
self.try(self.tp:command("pasv"))
local code, reply = self.try(self.tp:check("2.."))
local pattern = "(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)"
local a, b, c, d, p1, p2 = socket.skip(2, string.find(reply, pattern))
self.try(a and b and c and d and p1 and p2, reply)
self.pasvt = {
ip = string.format("%d.%d.%d.%d", a, b, c, d),
port = p1*256 + p2
}
if self.server then
self.server:close()
self.server = nil
end
return self.pasvt.ip, self.pasvt.port
end
function metat.__index:port(ip, port)
self.pasvt = nil
if not ip then
ip, port = self.try(self.tp:getcontrol():getsockname())
self.server = self.try(socket.bind(ip, 0))
ip, port = self.try(self.server:getsockname())
self.try(server:settimeout(TIMEOUT))
end
local pl = math.mod(port, 256)
local ph = (port - pl)/256
local arg = string.gsub(string.format("%s,%d,%d", ip, ph, pl), "%.", ",")
self.try(self.tp:command("port", arg))
self.try(self.tp:check("2.."))
return 1
end
function metat.__index:send(sendt)
self.try(self.pasvt or self.server, "need port or pasv first")
-- if there is a pasvt table, we already sent a PASV command
-- we just get the data connection into self.data
if self.pasvt then self:pasvconnect() end
-- get the transfer argument and command
local argument = sendt.argument or
url.unescape(string.gsub(sendt.path or "", "^[/\\]", ""))
if argument == "" then argument = nil end
local command = sendt.command or "stor"
-- send the transfer command and check the reply
self.try(self.tp:command(command, argument))
local code, reply = self.try(self.tp:check{"2..", "1.."})
-- if there is not a a pasvt table, then there is a server
-- and we already sent a PORT command
if not self.pasvt then self:portconnect() end
-- get the sink, source and step for the transfer
local step = sendt.step or ltn12.pump.step
local checkstep = function(src, snk)
-- check status in control connection while downloading
local readyt = socket.select(readt, nil, 0)
if readyt[tp] then self.try(self.tp:check("2..")) end
return step(src, snk)
end
local sink = socket.sink("close-when-done", self.data)
-- transfer all data and check error
self.try(ltn12.pump.all(sendt.source, sink, checkstep))
if string.find(code, "1..") then self.try(self.tp:check("2..")) end
-- done with data connection
self.data:close()
-- find out how many bytes were sent
local sent = socket.skip(1, self.data:getstats())
self.data = nil
return sent
end
function metat.__index:receive(recvt)
self.try(self.pasvt or self.server, "need port or pasv first")
if self.pasvt then self:pasvconnect() end
local argument = recvt.argument or
url.unescape(string.gsub(recvt.path or "", "^[/\\]", ""))
if argument == "" then argument = nil end
local command = recvt.command or "retr"
self.try(self.tp:command(command, argument))
local code = self.try(self.tp:check{"1..", "2.."})
if not self.pasvt then self:portconnect() end
local source = socket.source("until-closed", self.data)
local step = recvt.step or ltn12.pump.step
self.try(ltn12.pump.all(source, recvt.sink, step))
if string.find(code, "1..") then self.try(self.tp:check("2..")) end
self.data:close()
self.data = nil
return 1
end
function metat.__index:cwd(dir)
self.try(self.tp:command("cwd", dir))
self.try(self.tp:check(250))
return 1
end
function metat.__index:type(type)
self.try(self.tp:command("type", type))
self.try(self.tp:check(200))
return 1
end
function metat.__index:greet()
local code = self.try(self.tp:check{"1..", "2.."})
if string.find(code, "1..") then self.try(self.tp:check("2..")) end
return 1
end
function metat.__index:quit()
self.try(self.tp:command("quit"))
self.try(self.tp:check("2.."))
return 1
end
function metat.__index:close()
if self.data then self.data:close() end
if self.server then self.server:close() end
return self.tp:close()
end
-----------------------------------------------------------------------------
-- High level FTP API
-----------------------------------------------------------------------------
function override(t)
if t.url then
u = url.parse(t.url)
for i,v in base.pairs(t) do
u[i] = v
end
return u
else return t end
end
local function tput(putt)
putt = override(putt)
socket.try(putt.host, "missing hostname")
local f = open(putt.host, putt.port, putt.create)
f:greet()
f:login(putt.user, putt.password)
if putt.type then f:type(putt.type) end
f:pasv()
local sent = f:send(putt)
f:quit()
f:close()
return sent
end
local default = {
path = "/",
scheme = "ftp"
}
local function parse(u)
local t = socket.try(url.parse(u, default))
socket.try(t.scheme == "ftp", "wrong scheme '" .. t.scheme .. "'")
socket.try(t.host, "missing hostname")
local pat = "^type=(.)$"
if t.params then
t.type = socket.skip(2, string.find(t.params, pat))
socket.try(t.type == "a" or t.type == "i",
"invalid type '" .. t.type .. "'")
end
return t
end
local function sput(u, body)
local putt = parse(u)
putt.source = ltn12.source.string(body)
return tput(putt)
end
put = socket.protect(function(putt, body)
if base.type(putt) == "string" then return sput(putt, body)
else return tput(putt) end
end)
local function tget(gett)
gett = override(gett)
socket.try(gett.host, "missing hostname")
local f = open(gett.host, gett.port, gett.create)
f:greet()
f:login(gett.user, gett.password)
if gett.type then f:type(gett.type) end
f:pasv()
f:receive(gett)
f:quit()
return f:close()
end
local function sget(u)
local gett = parse(u)
local t = {}
gett.sink = ltn12.sink.table(t)
tget(gett)
return table.concat(t)
end
command = socket.protect(function(cmdt)
cmdt = override(cmdt)
socket.try(cmdt.host, "missing hostname")
socket.try(cmdt.command, "missing command")
local f = open(cmdt.host, cmdt.port, cmdt.create)
f:greet()
f:login(cmdt.user, cmdt.password)
f.try(f.tp:command(cmdt.command, cmdt.argument))
if cmdt.check then f.try(f.tp:check(cmdt.check)) end
f:quit()
return f:close()
end)
get = socket.protect(function(gett)
if base.type(gett) == "string" then return sget(gett)
else return tget(gett) end
end)

View File

@@ -1,326 +1,326 @@
-----------------------------------------------------------------------------
-- HTTP/1.1 client support for the Lua language.
-- LuaSocket toolkit.
-- Author: Diego Nehab
-- RCS ID: $Id: http.lua 1418 2006-04-25 09:38:15Z 3rdparty $
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
-- Declare module and import dependencies
-------------------------------------------------------------------------------
local socket = require("socket")
local url = require("socket.url")
local ltn12 = require("ltn12")
local mime = require("mime")
local string = require("string")
local base = _G
local table = require("table")
module("socket.http")
-----------------------------------------------------------------------------
-- Program constants
-----------------------------------------------------------------------------
-- connection timeout in seconds
TIMEOUT = 60
-- default port for document retrieval
PORT = 80
-- user agent field sent in request
USERAGENT = socket._VERSION
-----------------------------------------------------------------------------
-- Reads MIME headers from a connection, unfolding where needed
-----------------------------------------------------------------------------
local function receiveheaders(sock, headers)
local line, name, value, err
headers = headers or {}
-- get first line
line, err = sock:receive()
if err then return nil, err end
-- headers go until a blank line is found
while line ~= "" do
-- get field-name and value
name, value = socket.skip(2, string.find(line, "^(.-):%s*(.*)"))
if not (name and value) then return nil, "malformed reponse headers" end
name = string.lower(name)
-- get next line (value might be folded)
line, err = sock:receive()
if err then return nil, err end
-- unfold any folded values
while string.find(line, "^%s") do
value = value .. line
line = sock:receive()
if err then return nil, err end
end
-- save pair in table
if headers[name] then headers[name] = headers[name] .. ", " .. value
else headers[name] = value end
end
return headers
end
-----------------------------------------------------------------------------
-- Extra sources and sinks
-----------------------------------------------------------------------------
socket.sourcet["http-chunked"] = function(sock, headers)
return base.setmetatable({
getfd = function() return sock:getfd() end,
dirty = function() return sock:dirty() end
}, {
__call = function()
-- get chunk size, skip extention
local line, err = sock:receive()
if err then return nil, err end
local size = base.tonumber(string.gsub(line, ";.*", ""), 16)
if not size then return nil, "invalid chunk size" end
-- was it the last chunk?
if size > 0 then
-- if not, get chunk and skip terminating CRLF
local chunk, err, part = sock:receive(size)
if chunk then sock:receive() end
return chunk, err
else
-- if it was, read trailers into headers table
headers, err = receiveheaders(sock, headers)
if not headers then return nil, err end
end
end
})
end
socket.sinkt["http-chunked"] = function(sock)
return base.setmetatable({
getfd = function() return sock:getfd() end,
dirty = function() return sock:dirty() end
}, {
__call = function(self, chunk, err)
if not chunk then return sock:send("0\r\n\r\n") end
local size = string.format("%X\r\n", string.len(chunk))
return sock:send(size .. chunk .. "\r\n")
end
})
end
-----------------------------------------------------------------------------
-- Low level HTTP API
-----------------------------------------------------------------------------
local metat = { __index = {} }
function open(host, port, create)
-- create socket with user connect function, or with default
local c = socket.try(create or socket.tcp)()
local h = base.setmetatable({ c = c }, metat)
-- create finalized try
h.try = socket.newtry(function() h:close() end)
-- set timeout before connecting
h.try(c:settimeout(TIMEOUT))
h.try(c:connect(host, port or PORT))
-- here everything worked
return h
end
function metat.__index:sendrequestline(method, uri)
local reqline = string.format("%s %s HTTP/1.1\r\n", method or "GET", uri)
return self.try(self.c:send(reqline))
end
function metat.__index:sendheaders(headers)
local h = "\r\n"
for i, v in base.pairs(headers) do
h = i .. ": " .. v .. "\r\n" .. h
end
self.try(self.c:send(h))
return 1
end
function metat.__index:sendbody(headers, source, step)
source = source or ltn12.source.empty()
step = step or ltn12.pump.step
-- if we don't know the size in advance, send chunked and hope for the best
local mode = "http-chunked"
if headers["content-length"] then mode = "keep-open" end
return self.try(ltn12.pump.all(source, socket.sink(mode, self.c), step))
end
function metat.__index:receivestatusline()
local status = self.try(self.c:receive())
local code = socket.skip(2, string.find(status, "HTTP/%d*%.%d* (%d%d%d)"))
return self.try(base.tonumber(code), status)
end
function metat.__index:receiveheaders()
return self.try(receiveheaders(self.c))
end
function metat.__index:receivebody(headers, sink, step)
sink = sink or ltn12.sink.null()
step = step or ltn12.pump.step
local length = base.tonumber(headers["content-length"])
local t = headers["transfer-encoding"] -- shortcut
local mode = "default" -- connection close
if t and t ~= "identity" then mode = "http-chunked"
elseif base.tonumber(headers["content-length"]) then mode = "by-length" end
return self.try(ltn12.pump.all(socket.source(mode, self.c, length),
sink, step))
end
function metat.__index:close()
return self.c:close()
end
-----------------------------------------------------------------------------
-- High level HTTP API
-----------------------------------------------------------------------------
local function adjusturi(reqt)
local u = reqt
-- if there is a proxy, we need the full url. otherwise, just a part.
if not reqt.proxy and not PROXY then
u = {
path = socket.try(reqt.path, "invalid path 'nil'"),
params = reqt.params,
query = reqt.query,
fragment = reqt.fragment
}
end
return url.build(u)
end
local function adjustproxy(reqt)
local proxy = reqt.proxy or PROXY
if proxy then
proxy = url.parse(proxy)
return proxy.host, proxy.port or 3128
else
return reqt.host, reqt.port
end
end
local function adjustheaders(headers, host)
-- default headers
local lower = {
["user-agent"] = USERAGENT,
["host"] = host,
["connection"] = "close, TE",
["te"] = "trailers"
}
-- override with user headers
for i,v in base.pairs(headers or lower) do
lower[string.lower(i)] = v
end
return lower
end
-- default url parts
local default = {
host = "",
port = PORT,
path ="/",
scheme = "http"
}
local function adjustrequest(reqt)
-- parse url if provided
local nreqt = reqt.url and url.parse(reqt.url, default) or {}
local t = url.parse(reqt.url, default)
-- explicit components override url
for i,v in base.pairs(reqt) do nreqt[i] = v end
socket.try(nreqt.host, "invalid host '" .. base.tostring(nreqt.host) .. "'")
-- compute uri if user hasn't overriden
nreqt.uri = reqt.uri or adjusturi(nreqt)
-- ajust host and port if there is a proxy
nreqt.host, nreqt.port = adjustproxy(nreqt)
-- adjust headers in request
nreqt.headers = adjustheaders(nreqt.headers, nreqt.host)
return nreqt
end
local function shouldredirect(reqt, code, headers)
return headers.location and
string.gsub(headers.location, "%s", "") ~= "" and
(reqt.redirect ~= false) and
(code == 301 or code == 302) and
(not reqt.method or reqt.method == "GET" or reqt.method == "HEAD")
and (not reqt.nredirects or reqt.nredirects < 5)
end
local function shouldauthorize(reqt, code)
-- if there has been an authorization attempt, it must have failed
if reqt.headers and reqt.headers["authorization"] then return nil end
-- if last attempt didn't fail due to lack of authentication,
-- or we don't have authorization information, we can't retry
return code == 401 and reqt.user and reqt.password
end
local function shouldreceivebody(reqt, code)
if reqt.method == "HEAD" then return nil end
if code == 204 or code == 304 then return nil end
if code >= 100 and code < 200 then return nil end
return 1
end
-- forward declarations
local trequest, tauthorize, tredirect
function tauthorize(reqt)
local auth = "Basic " .. (mime.b64(reqt.user .. ":" .. reqt.password))
reqt.headers["authorization"] = auth
return trequest(reqt)
end
function tredirect(reqt, location)
local result, code, headers, status = trequest {
-- the RFC says the redirect URL has to be absolute, but some
-- servers do not respect that
url = url.absolute(reqt, location),
source = reqt.source,
sink = reqt.sink,
headers = reqt.headers,
proxy = reqt.proxy,
nredirects = (reqt.nredirects or 0) + 1,
connect = reqt.connect
}
-- pass location header back as a hint we redirected
headers.location = headers.location or location
return result, code, headers, status
end
function trequest(reqt)
reqt = adjustrequest(reqt)
local h = open(reqt.host, reqt.port, reqt.create)
h:sendrequestline(reqt.method, reqt.uri)
h:sendheaders(reqt.headers)
if reqt.source then h:sendbody(reqt.headers, reqt.source, reqt.step) end
local code, headers, status
code, status = h:receivestatusline()
headers = h:receiveheaders()
if shouldredirect(reqt, code, headers) then
h:close()
return tredirect(reqt, headers.location)
elseif shouldauthorize(reqt, code) then
h:close()
return tauthorize(reqt)
elseif shouldreceivebody(reqt, code) then
h:receivebody(headers, reqt.sink, reqt.step)
end
h:close()
return 1, code, headers, status
end
local function srequest(u, body)
local t = {}
local reqt = {
url = u,
sink = ltn12.sink.table(t)
}
if body then
reqt.source = ltn12.source.string(body)
reqt.headers = { ["content-length"] = string.len(body) }
reqt.method = "POST"
end
local code, headers, status = socket.skip(1, trequest(reqt))
return table.concat(t), code, headers, status
end
request = socket.protect(function(reqt, body)
if base.type(reqt) == "string" then return srequest(reqt, body)
else return trequest(reqt) end
end)
-----------------------------------------------------------------------------
-- HTTP/1.1 client support for the Lua language.
-- LuaSocket toolkit.
-- Author: Diego Nehab
-- RCS ID: $Id: http.lua 1418 2006-04-25 09:38:15Z 3rdparty $
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
-- Declare module and import dependencies
-------------------------------------------------------------------------------
local socket = require("socket")
local url = require("socket.url")
local ltn12 = require("ltn12")
local mime = require("mime")
local string = require("string")
local base = _G
local table = require("table")
module("socket.http")
-----------------------------------------------------------------------------
-- Program constants
-----------------------------------------------------------------------------
-- connection timeout in seconds
TIMEOUT = 60
-- default port for document retrieval
PORT = 80
-- user agent field sent in request
USERAGENT = socket._VERSION
-----------------------------------------------------------------------------
-- Reads MIME headers from a connection, unfolding where needed
-----------------------------------------------------------------------------
local function receiveheaders(sock, headers)
local line, name, value, err
headers = headers or {}
-- get first line
line, err = sock:receive()
if err then return nil, err end
-- headers go until a blank line is found
while line ~= "" do
-- get field-name and value
name, value = socket.skip(2, string.find(line, "^(.-):%s*(.*)"))
if not (name and value) then return nil, "malformed reponse headers" end
name = string.lower(name)
-- get next line (value might be folded)
line, err = sock:receive()
if err then return nil, err end
-- unfold any folded values
while string.find(line, "^%s") do
value = value .. line
line = sock:receive()
if err then return nil, err end
end
-- save pair in table
if headers[name] then headers[name] = headers[name] .. ", " .. value
else headers[name] = value end
end
return headers
end
-----------------------------------------------------------------------------
-- Extra sources and sinks
-----------------------------------------------------------------------------
socket.sourcet["http-chunked"] = function(sock, headers)
return base.setmetatable({
getfd = function() return sock:getfd() end,
dirty = function() return sock:dirty() end
}, {
__call = function()
-- get chunk size, skip extention
local line, err = sock:receive()
if err then return nil, err end
local size = base.tonumber(string.gsub(line, ";.*", ""), 16)
if not size then return nil, "invalid chunk size" end
-- was it the last chunk?
if size > 0 then
-- if not, get chunk and skip terminating CRLF
local chunk, err, part = sock:receive(size)
if chunk then sock:receive() end
return chunk, err
else
-- if it was, read trailers into headers table
headers, err = receiveheaders(sock, headers)
if not headers then return nil, err end
end
end
})
end
socket.sinkt["http-chunked"] = function(sock)
return base.setmetatable({
getfd = function() return sock:getfd() end,
dirty = function() return sock:dirty() end
}, {
__call = function(self, chunk, err)
if not chunk then return sock:send("0\r\n\r\n") end
local size = string.format("%X\r\n", string.len(chunk))
return sock:send(size .. chunk .. "\r\n")
end
})
end
-----------------------------------------------------------------------------
-- Low level HTTP API
-----------------------------------------------------------------------------
local metat = { __index = {} }
function open(host, port, create)
-- create socket with user connect function, or with default
local c = socket.try(create or socket.tcp)()
local h = base.setmetatable({ c = c }, metat)
-- create finalized try
h.try = socket.newtry(function() h:close() end)
-- set timeout before connecting
h.try(c:settimeout(TIMEOUT))
h.try(c:connect(host, port or PORT))
-- here everything worked
return h
end
function metat.__index:sendrequestline(method, uri)
local reqline = string.format("%s %s HTTP/1.1\r\n", method or "GET", uri)
return self.try(self.c:send(reqline))
end
function metat.__index:sendheaders(headers)
local h = "\r\n"
for i, v in base.pairs(headers) do
h = i .. ": " .. v .. "\r\n" .. h
end
self.try(self.c:send(h))
return 1
end
function metat.__index:sendbody(headers, source, step)
source = source or ltn12.source.empty()
step = step or ltn12.pump.step
-- if we don't know the size in advance, send chunked and hope for the best
local mode = "http-chunked"
if headers["content-length"] then mode = "keep-open" end
return self.try(ltn12.pump.all(source, socket.sink(mode, self.c), step))
end
function metat.__index:receivestatusline()
local status = self.try(self.c:receive())
local code = socket.skip(2, string.find(status, "HTTP/%d*%.%d* (%d%d%d)"))
return self.try(base.tonumber(code), status)
end
function metat.__index:receiveheaders()
return self.try(receiveheaders(self.c))
end
function metat.__index:receivebody(headers, sink, step)
sink = sink or ltn12.sink.null()
step = step or ltn12.pump.step
local length = base.tonumber(headers["content-length"])
local t = headers["transfer-encoding"] -- shortcut
local mode = "default" -- connection close
if t and t ~= "identity" then mode = "http-chunked"
elseif base.tonumber(headers["content-length"]) then mode = "by-length" end
return self.try(ltn12.pump.all(socket.source(mode, self.c, length),
sink, step))
end
function metat.__index:close()
return self.c:close()
end
-----------------------------------------------------------------------------
-- High level HTTP API
-----------------------------------------------------------------------------
local function adjusturi(reqt)
local u = reqt
-- if there is a proxy, we need the full url. otherwise, just a part.
if not reqt.proxy and not PROXY then
u = {
path = socket.try(reqt.path, "invalid path 'nil'"),
params = reqt.params,
query = reqt.query,
fragment = reqt.fragment
}
end
return url.build(u)
end
local function adjustproxy(reqt)
local proxy = reqt.proxy or PROXY
if proxy then
proxy = url.parse(proxy)
return proxy.host, proxy.port or 3128
else
return reqt.host, reqt.port
end
end
local function adjustheaders(headers, host)
-- default headers
local lower = {
["user-agent"] = USERAGENT,
["host"] = host,
["connection"] = "close, TE",
["te"] = "trailers"
}
-- override with user headers
for i,v in base.pairs(headers or lower) do
lower[string.lower(i)] = v
end
return lower
end
-- default url parts
local default = {
host = "",
port = PORT,
path ="/",
scheme = "http"
}
local function adjustrequest(reqt)
-- parse url if provided
local nreqt = reqt.url and url.parse(reqt.url, default) or {}
local t = url.parse(reqt.url, default)
-- explicit components override url
for i,v in base.pairs(reqt) do nreqt[i] = v end
socket.try(nreqt.host, "invalid host '" .. base.tostring(nreqt.host) .. "'")
-- compute uri if user hasn't overriden
nreqt.uri = reqt.uri or adjusturi(nreqt)
-- ajust host and port if there is a proxy
nreqt.host, nreqt.port = adjustproxy(nreqt)
-- adjust headers in request
nreqt.headers = adjustheaders(nreqt.headers, nreqt.host)
return nreqt
end
local function shouldredirect(reqt, code, headers)
return headers.location and
string.gsub(headers.location, "%s", "") ~= "" and
(reqt.redirect ~= false) and
(code == 301 or code == 302) and
(not reqt.method or reqt.method == "GET" or reqt.method == "HEAD")
and (not reqt.nredirects or reqt.nredirects < 5)
end
local function shouldauthorize(reqt, code)
-- if there has been an authorization attempt, it must have failed
if reqt.headers and reqt.headers["authorization"] then return nil end
-- if last attempt didn't fail due to lack of authentication,
-- or we don't have authorization information, we can't retry
return code == 401 and reqt.user and reqt.password
end
local function shouldreceivebody(reqt, code)
if reqt.method == "HEAD" then return nil end
if code == 204 or code == 304 then return nil end
if code >= 100 and code < 200 then return nil end
return 1
end
-- forward declarations
local trequest, tauthorize, tredirect
function tauthorize(reqt)
local auth = "Basic " .. (mime.b64(reqt.user .. ":" .. reqt.password))
reqt.headers["authorization"] = auth
return trequest(reqt)
end
function tredirect(reqt, location)
local result, code, headers, status = trequest {
-- the RFC says the redirect URL has to be absolute, but some
-- servers do not respect that
url = url.absolute(reqt, location),
source = reqt.source,
sink = reqt.sink,
headers = reqt.headers,
proxy = reqt.proxy,
nredirects = (reqt.nredirects or 0) + 1,
connect = reqt.connect
}
-- pass location header back as a hint we redirected
headers.location = headers.location or location
return result, code, headers, status
end
function trequest(reqt)
reqt = adjustrequest(reqt)
local h = open(reqt.host, reqt.port, reqt.create)
h:sendrequestline(reqt.method, reqt.uri)
h:sendheaders(reqt.headers)
if reqt.source then h:sendbody(reqt.headers, reqt.source, reqt.step) end
local code, headers, status
code, status = h:receivestatusline()
headers = h:receiveheaders()
if shouldredirect(reqt, code, headers) then
h:close()
return tredirect(reqt, headers.location)
elseif shouldauthorize(reqt, code) then
h:close()
return tauthorize(reqt)
elseif shouldreceivebody(reqt, code) then
h:receivebody(headers, reqt.sink, reqt.step)
end
h:close()
return 1, code, headers, status
end
local function srequest(u, body)
local t = {}
local reqt = {
url = u,
sink = ltn12.sink.table(t)
}
if body then
reqt.source = ltn12.source.string(body)
reqt.headers = { ["content-length"] = string.len(body) }
reqt.method = "POST"
end
local code, headers, status = socket.skip(1, trequest(reqt))
return table.concat(t), code, headers, status
end
request = socket.protect(function(reqt, body)
if base.type(reqt) == "string" then return srequest(reqt, body)
else return trequest(reqt) end
end)

View File

@@ -1,245 +1,245 @@
-----------------------------------------------------------------------------
-- SMTP client support for the Lua language.
-- LuaSocket toolkit.
-- Author: Diego Nehab
-- RCS ID: $Id: smtp.lua 1418 2006-04-25 09:38:15Z 3rdparty $
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
-- Declare module and import dependencies
-----------------------------------------------------------------------------
local base = _G
local coroutine = require("coroutine")
local string = require("string")
local math = require("math")
local os = require("os")
local socket = require("socket")
local tp = require("socket.tp")
local ltn12 = require("ltn12")
local mime = require("mime")
module("socket.smtp")
-----------------------------------------------------------------------------
-- Program constants
-----------------------------------------------------------------------------
-- timeout for connection
TIMEOUT = 60
-- default server used to send e-mails
SERVER = "localhost"
-- default port
PORT = 25
-- domain used in HELO command and default sendmail
-- If we are under a CGI, try to get from environment
DOMAIN = os.getenv("SERVER_NAME") or "localhost"
-- default time zone (means we don't know)
ZONE = "-0000"
---------------------------------------------------------------------------
-- Low level SMTP API
-----------------------------------------------------------------------------
local metat = { __index = {} }
function metat.__index:greet(domain)
self.try(self.tp:check("2.."))
self.try(self.tp:command("EHLO", domain or DOMAIN))
return socket.skip(1, self.try(self.tp:check("2..")))
end
function metat.__index:mail(from)
self.try(self.tp:command("MAIL", "FROM:" .. from))
return self.try(self.tp:check("2.."))
end
function metat.__index:rcpt(to)
self.try(self.tp:command("RCPT", "TO:" .. to))
return self.try(self.tp:check("2.."))
end
function metat.__index:data(src, step)
self.try(self.tp:command("DATA"))
self.try(self.tp:check("3.."))
self.try(self.tp:source(src, step))
self.try(self.tp:send("\r\n.\r\n"))
return self.try(self.tp:check("2.."))
end
function metat.__index:quit()
self.try(self.tp:command("QUIT"))
return self.try(self.tp:check("2.."))
end
function metat.__index:close()
return self.tp:close()
end
function metat.__index:login(user, password)
self.try(self.tp:command("AUTH", "LOGIN"))
self.try(self.tp:check("3.."))
self.try(self.tp:command(mime.b64(user)))
self.try(self.tp:check("3.."))
self.try(self.tp:command(mime.b64(password)))
return self.try(self.tp:check("2.."))
end
function metat.__index:plain(user, password)
local auth = "PLAIN " .. mime.b64("\0" .. user .. "\0" .. password)
self.try(self.tp:command("AUTH", auth))
return self.try(self.tp:check("2.."))
end
function metat.__index:auth(user, password, ext)
if not user or not password then return 1 end
if string.find(ext, "AUTH[^\n]+LOGIN") then
return self:login(user, password)
elseif string.find(ext, "AUTH[^\n]+PLAIN") then
return self:plain(user, password)
else
self.try(nil, "authentication not supported")
end
end
-- send message or throw an exception
function metat.__index:send(mailt)
self:mail(mailt.from)
if base.type(mailt.rcpt) == "table" then
for i,v in base.ipairs(mailt.rcpt) do
self:rcpt(v)
end
else
self:rcpt(mailt.rcpt)
end
self:data(ltn12.source.chain(mailt.source, mime.stuff()), mailt.step)
end
function open(server, port, create)
local tp = socket.try(tp.connect(server or SERVER, port or PORT,
create, TIMEOUT))
local s = base.setmetatable({tp = tp}, metat)
-- make sure tp is closed if we get an exception
s.try = socket.newtry(function()
s:close()
end)
return s
end
---------------------------------------------------------------------------
-- Multipart message source
-----------------------------------------------------------------------------
-- returns a hopefully unique mime boundary
local seqno = 0
local function newboundary()
seqno = seqno + 1
return string.format('%s%05d==%05u', os.date('%d%m%Y%H%M%S'),
math.random(0, 99999), seqno)
end
-- send_message forward declaration
local send_message
-- yield the headers all at once, it's faster
local function send_headers(headers)
local h = "\r\n"
for i,v in base.pairs(headers) do
h = i .. ': ' .. v .. "\r\n" .. h
end
coroutine.yield(h)
end
-- yield multipart message body from a multipart message table
local function send_multipart(mesgt)
-- make sure we have our boundary and send headers
local bd = newboundary()
local headers = mesgt.headers or {}
headers['content-type'] = headers['content-type'] or 'multipart/mixed'
headers['content-type'] = headers['content-type'] ..
'; boundary="' .. bd .. '"'
send_headers(headers)
-- send preamble
if mesgt.body.preamble then
coroutine.yield(mesgt.body.preamble)
coroutine.yield("\r\n")
end
-- send each part separated by a boundary
for i, m in base.ipairs(mesgt.body) do
coroutine.yield("\r\n--" .. bd .. "\r\n")
send_message(m)
end
-- send last boundary
coroutine.yield("\r\n--" .. bd .. "--\r\n\r\n")
-- send epilogue
if mesgt.body.epilogue then
coroutine.yield(mesgt.body.epilogue)
coroutine.yield("\r\n")
end
end
-- yield message body from a source
local function send_source(mesgt)
-- make sure we have a content-type
local headers = mesgt.headers or {}
headers['content-type'] = headers['content-type'] or
'text/plain; charset="iso-8859-1"'
send_headers(headers)
-- send body from source
while true do
local chunk, err = mesgt.body()
if err then coroutine.yield(nil, err)
elseif chunk then coroutine.yield(chunk)
else break end
end
end
-- yield message body from a string
local function send_string(mesgt)
-- make sure we have a content-type
local headers = mesgt.headers or {}
headers['content-type'] = headers['content-type'] or
'text/plain; charset="iso-8859-1"'
send_headers(headers)
-- send body from string
coroutine.yield(mesgt.body)
end
-- message source
function send_message(mesgt)
if base.type(mesgt.body) == "table" then send_multipart(mesgt)
elseif base.type(mesgt.body) == "function" then send_source(mesgt)
else send_string(mesgt) end
end
-- set defaul headers
local function adjust_headers(mesgt)
local lower = {}
for i,v in base.pairs(mesgt.headers or lower) do
lower[string.lower(i)] = v
end
lower["date"] = lower["date"] or
os.date("!%a, %d %b %Y %H:%M:%S ") .. (mesgt.zone or ZONE)
lower["x-mailer"] = lower["x-mailer"] or socket._VERSION
-- this can't be overriden
lower["mime-version"] = "1.0"
mesgt.headers = lower
end
function message(mesgt)
adjust_headers(mesgt)
-- create and return message source
local co = coroutine.create(function() send_message(mesgt) end)
return function()
local ret, a, b = coroutine.resume(co)
if ret then return a, b
else return nil, a end
end
end
---------------------------------------------------------------------------
-- High level SMTP API
-----------------------------------------------------------------------------
send = socket.protect(function(mailt)
local s = open(mailt.server, mailt.port, mailt.create)
local ext = s:greet(mailt.domain)
s:auth(mailt.user, mailt.password, ext)
s:send(mailt)
s:quit()
return s:close()
end)
-----------------------------------------------------------------------------
-- SMTP client support for the Lua language.
-- LuaSocket toolkit.
-- Author: Diego Nehab
-- RCS ID: $Id: smtp.lua 1418 2006-04-25 09:38:15Z 3rdparty $
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
-- Declare module and import dependencies
-----------------------------------------------------------------------------
local base = _G
local coroutine = require("coroutine")
local string = require("string")
local math = require("math")
local os = require("os")
local socket = require("socket")
local tp = require("socket.tp")
local ltn12 = require("ltn12")
local mime = require("mime")
module("socket.smtp")
-----------------------------------------------------------------------------
-- Program constants
-----------------------------------------------------------------------------
-- timeout for connection
TIMEOUT = 60
-- default server used to send e-mails
SERVER = "localhost"
-- default port
PORT = 25
-- domain used in HELO command and default sendmail
-- If we are under a CGI, try to get from environment
DOMAIN = os.getenv("SERVER_NAME") or "localhost"
-- default time zone (means we don't know)
ZONE = "-0000"
---------------------------------------------------------------------------
-- Low level SMTP API
-----------------------------------------------------------------------------
local metat = { __index = {} }
function metat.__index:greet(domain)
self.try(self.tp:check("2.."))
self.try(self.tp:command("EHLO", domain or DOMAIN))
return socket.skip(1, self.try(self.tp:check("2..")))
end
function metat.__index:mail(from)
self.try(self.tp:command("MAIL", "FROM:" .. from))
return self.try(self.tp:check("2.."))
end
function metat.__index:rcpt(to)
self.try(self.tp:command("RCPT", "TO:" .. to))
return self.try(self.tp:check("2.."))
end
function metat.__index:data(src, step)
self.try(self.tp:command("DATA"))
self.try(self.tp:check("3.."))
self.try(self.tp:source(src, step))
self.try(self.tp:send("\r\n.\r\n"))
return self.try(self.tp:check("2.."))
end
function metat.__index:quit()
self.try(self.tp:command("QUIT"))
return self.try(self.tp:check("2.."))
end
function metat.__index:close()
return self.tp:close()
end
function metat.__index:login(user, password)
self.try(self.tp:command("AUTH", "LOGIN"))
self.try(self.tp:check("3.."))
self.try(self.tp:command(mime.b64(user)))
self.try(self.tp:check("3.."))
self.try(self.tp:command(mime.b64(password)))
return self.try(self.tp:check("2.."))
end
function metat.__index:plain(user, password)
local auth = "PLAIN " .. mime.b64("\0" .. user .. "\0" .. password)
self.try(self.tp:command("AUTH", auth))
return self.try(self.tp:check("2.."))
end
function metat.__index:auth(user, password, ext)
if not user or not password then return 1 end
if string.find(ext, "AUTH[^\n]+LOGIN") then
return self:login(user, password)
elseif string.find(ext, "AUTH[^\n]+PLAIN") then
return self:plain(user, password)
else
self.try(nil, "authentication not supported")
end
end
-- send message or throw an exception
function metat.__index:send(mailt)
self:mail(mailt.from)
if base.type(mailt.rcpt) == "table" then
for i,v in base.ipairs(mailt.rcpt) do
self:rcpt(v)
end
else
self:rcpt(mailt.rcpt)
end
self:data(ltn12.source.chain(mailt.source, mime.stuff()), mailt.step)
end
function open(server, port, create)
local tp = socket.try(tp.connect(server or SERVER, port or PORT,
create, TIMEOUT))
local s = base.setmetatable({tp = tp}, metat)
-- make sure tp is closed if we get an exception
s.try = socket.newtry(function()
s:close()
end)
return s
end
---------------------------------------------------------------------------
-- Multipart message source
-----------------------------------------------------------------------------
-- returns a hopefully unique mime boundary
local seqno = 0
local function newboundary()
seqno = seqno + 1
return string.format('%s%05d==%05u', os.date('%d%m%Y%H%M%S'),
math.random(0, 99999), seqno)
end
-- send_message forward declaration
local send_message
-- yield the headers all at once, it's faster
local function send_headers(headers)
local h = "\r\n"
for i,v in base.pairs(headers) do
h = i .. ': ' .. v .. "\r\n" .. h
end
coroutine.yield(h)
end
-- yield multipart message body from a multipart message table
local function send_multipart(mesgt)
-- make sure we have our boundary and send headers
local bd = newboundary()
local headers = mesgt.headers or {}
headers['content-type'] = headers['content-type'] or 'multipart/mixed'
headers['content-type'] = headers['content-type'] ..
'; boundary="' .. bd .. '"'
send_headers(headers)
-- send preamble
if mesgt.body.preamble then
coroutine.yield(mesgt.body.preamble)
coroutine.yield("\r\n")
end
-- send each part separated by a boundary
for i, m in base.ipairs(mesgt.body) do
coroutine.yield("\r\n--" .. bd .. "\r\n")
send_message(m)
end
-- send last boundary
coroutine.yield("\r\n--" .. bd .. "--\r\n\r\n")
-- send epilogue
if mesgt.body.epilogue then
coroutine.yield(mesgt.body.epilogue)
coroutine.yield("\r\n")
end
end
-- yield message body from a source
local function send_source(mesgt)
-- make sure we have a content-type
local headers = mesgt.headers or {}
headers['content-type'] = headers['content-type'] or
'text/plain; charset="iso-8859-1"'
send_headers(headers)
-- send body from source
while true do
local chunk, err = mesgt.body()
if err then coroutine.yield(nil, err)
elseif chunk then coroutine.yield(chunk)
else break end
end
end
-- yield message body from a string
local function send_string(mesgt)
-- make sure we have a content-type
local headers = mesgt.headers or {}
headers['content-type'] = headers['content-type'] or
'text/plain; charset="iso-8859-1"'
send_headers(headers)
-- send body from string
coroutine.yield(mesgt.body)
end
-- message source
function send_message(mesgt)
if base.type(mesgt.body) == "table" then send_multipart(mesgt)
elseif base.type(mesgt.body) == "function" then send_source(mesgt)
else send_string(mesgt) end
end
-- set defaul headers
local function adjust_headers(mesgt)
local lower = {}
for i,v in base.pairs(mesgt.headers or lower) do
lower[string.lower(i)] = v
end
lower["date"] = lower["date"] or
os.date("!%a, %d %b %Y %H:%M:%S ") .. (mesgt.zone or ZONE)
lower["x-mailer"] = lower["x-mailer"] or socket._VERSION
-- this can't be overriden
lower["mime-version"] = "1.0"
mesgt.headers = lower
end
function message(mesgt)
adjust_headers(mesgt)
-- create and return message source
local co = coroutine.create(function() send_message(mesgt) end)
return function()
local ret, a, b = coroutine.resume(co)
if ret then return a, b
else return nil, a end
end
end
---------------------------------------------------------------------------
-- High level SMTP API
-----------------------------------------------------------------------------
send = socket.protect(function(mailt)
local s = open(mailt.server, mailt.port, mailt.create)
local ext = s:greet(mailt.domain)
s:auth(mailt.user, mailt.password, ext)
s:send(mailt)
s:quit()
return s:close()
end)

View File

@@ -1,123 +1,123 @@
-----------------------------------------------------------------------------
-- Unified SMTP/FTP subsystem
-- LuaSocket toolkit.
-- Author: Diego Nehab
-- RCS ID: $Id: tp.lua 1418 2006-04-25 09:38:15Z 3rdparty $
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
-- Declare module and import dependencies
-----------------------------------------------------------------------------
local base = _G
local string = require("string")
local socket = require("socket")
local ltn12 = require("ltn12")
module("socket.tp")
-----------------------------------------------------------------------------
-- Program constants
-----------------------------------------------------------------------------
TIMEOUT = 60
-----------------------------------------------------------------------------
-- Implementation
-----------------------------------------------------------------------------
-- gets server reply (works for SMTP and FTP)
local function get_reply(c)
local code, current, sep
local line, err = c:receive()
local reply = line
if err then return nil, err end
code, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)"))
if not code then return nil, "invalid server reply" end
if sep == "-" then -- reply is multiline
repeat
line, err = c:receive()
if err then return nil, err end
current, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)"))
reply = reply .. "\n" .. line
-- reply ends with same code
until code == current and sep == " "
end
return code, reply
end
-- metatable for sock object
local metat = { __index = {} }
function metat.__index:check(ok)
local code, reply = get_reply(self.c)
if not code then return nil, reply end
if base.type(ok) ~= "function" then
if base.type(ok) == "table" then
for i, v in base.ipairs(ok) do
if string.find(code, v) then
return base.tonumber(code), reply
end
end
return nil, reply
else
if string.find(code, ok) then return base.tonumber(code), reply
else return nil, reply end
end
else return ok(base.tonumber(code), reply) end
end
function metat.__index:command(cmd, arg)
if arg then
return self.c:send(cmd .. " " .. arg.. "\r\n")
else
return self.c:send(cmd .. "\r\n")
end
end
function metat.__index:sink(snk, pat)
local chunk, err = c:receive(pat)
return snk(chunk, err)
end
function metat.__index:send(data)
return self.c:send(data)
end
function metat.__index:receive(pat)
return self.c:receive(pat)
end
function metat.__index:getfd()
return self.c:getfd()
end
function metat.__index:dirty()
return self.c:dirty()
end
function metat.__index:getcontrol()
return self.c
end
function metat.__index:source(source, step)
local sink = socket.sink("keep-open", self.c)
local ret, err = ltn12.pump.all(source, sink, step or ltn12.pump.step)
return ret, err
end
-- closes the underlying c
function metat.__index:close()
self.c:close()
return 1
end
-- connect with server and return c object
function connect(host, port, create, timeout)
local c, e = (create or socket.tcp())
if not c then return nil, e end
c:settimeout(timeout or TIMEOUT)
local r, e = c:connect(host, port)
if not r then
c:close()
return nil, e
end
return base.setmetatable({c = c}, metat)
end
-----------------------------------------------------------------------------
-- Unified SMTP/FTP subsystem
-- LuaSocket toolkit.
-- Author: Diego Nehab
-- RCS ID: $Id: tp.lua 1418 2006-04-25 09:38:15Z 3rdparty $
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
-- Declare module and import dependencies
-----------------------------------------------------------------------------
local base = _G
local string = require("string")
local socket = require("socket")
local ltn12 = require("ltn12")
module("socket.tp")
-----------------------------------------------------------------------------
-- Program constants
-----------------------------------------------------------------------------
TIMEOUT = 60
-----------------------------------------------------------------------------
-- Implementation
-----------------------------------------------------------------------------
-- gets server reply (works for SMTP and FTP)
local function get_reply(c)
local code, current, sep
local line, err = c:receive()
local reply = line
if err then return nil, err end
code, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)"))
if not code then return nil, "invalid server reply" end
if sep == "-" then -- reply is multiline
repeat
line, err = c:receive()
if err then return nil, err end
current, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)"))
reply = reply .. "\n" .. line
-- reply ends with same code
until code == current and sep == " "
end
return code, reply
end
-- metatable for sock object
local metat = { __index = {} }
function metat.__index:check(ok)
local code, reply = get_reply(self.c)
if not code then return nil, reply end
if base.type(ok) ~= "function" then
if base.type(ok) == "table" then
for i, v in base.ipairs(ok) do
if string.find(code, v) then
return base.tonumber(code), reply
end
end
return nil, reply
else
if string.find(code, ok) then return base.tonumber(code), reply
else return nil, reply end
end
else return ok(base.tonumber(code), reply) end
end
function metat.__index:command(cmd, arg)
if arg then
return self.c:send(cmd .. " " .. arg.. "\r\n")
else
return self.c:send(cmd .. "\r\n")
end
end
function metat.__index:sink(snk, pat)
local chunk, err = c:receive(pat)
return snk(chunk, err)
end
function metat.__index:send(data)
return self.c:send(data)
end
function metat.__index:receive(pat)
return self.c:receive(pat)
end
function metat.__index:getfd()
return self.c:getfd()
end
function metat.__index:dirty()
return self.c:dirty()
end
function metat.__index:getcontrol()
return self.c
end
function metat.__index:source(source, step)
local sink = socket.sink("keep-open", self.c)
local ret, err = ltn12.pump.all(source, sink, step or ltn12.pump.step)
return ret, err
end
-- closes the underlying c
function metat.__index:close()
self.c:close()
return 1
end
-- connect with server and return c object
function connect(host, port, create, timeout)
local c, e = (create or socket.tcp())
if not c then return nil, e end
c:settimeout(timeout or TIMEOUT)
local r, e = c:connect(host, port)
if not r then
c:close()
return nil, e
end
return base.setmetatable({c = c}, metat)
end

View File

@@ -1,297 +1,297 @@
-----------------------------------------------------------------------------
-- URI parsing, composition and relative URL resolution
-- LuaSocket toolkit.
-- Author: Diego Nehab
-- RCS ID: $Id: url.lua 1418 2006-04-25 09:38:15Z 3rdparty $
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
-- Declare module
-----------------------------------------------------------------------------
local string = require("string")
local base = _G
local table = require("table")
module("socket.url")
-----------------------------------------------------------------------------
-- Module version
-----------------------------------------------------------------------------
_VERSION = "URL 1.0"
-----------------------------------------------------------------------------
-- Encodes a string into its escaped hexadecimal representation
-- Input
-- s: binary string to be encoded
-- Returns
-- escaped representation of string binary
-----------------------------------------------------------------------------
function escape(s)
return string.gsub(s, "([^A-Za-z0-9_])", function(c)
return string.format("%%%02x", string.byte(c))
end)
end
-----------------------------------------------------------------------------
-- Protects a path segment, to prevent it from interfering with the
-- url parsing.
-- Input
-- s: binary string to be encoded
-- Returns
-- escaped representation of string binary
-----------------------------------------------------------------------------
local function make_set(t)
local s = {}
for i,v in base.ipairs(t) do
s[t[i]] = 1
end
return s
end
-- these are allowed withing a path segment, along with alphanum
-- other characters must be escaped
local segment_set = make_set {
"-", "_", ".", "!", "~", "*", "'", "(",
")", ":", "@", "&", "=", "+", "$", ",",
}
local function protect_segment(s)
return string.gsub(s, "([^A-Za-z0-9_])", function (c)
if segment_set[c] then return c
else return string.format("%%%02x", string.byte(c)) end
end)
end
-----------------------------------------------------------------------------
-- Encodes a string into its escaped hexadecimal representation
-- Input
-- s: binary string to be encoded
-- Returns
-- escaped representation of string binary
-----------------------------------------------------------------------------
function unescape(s)
return string.gsub(s, "%%(%x%x)", function(hex)
return string.char(base.tonumber(hex, 16))
end)
end
-----------------------------------------------------------------------------
-- Builds a path from a base path and a relative path
-- Input
-- base_path
-- relative_path
-- Returns
-- corresponding absolute path
-----------------------------------------------------------------------------
local function absolute_path(base_path, relative_path)
if string.sub(relative_path, 1, 1) == "/" then return relative_path end
local path = string.gsub(base_path, "[^/]*$", "")
path = path .. relative_path
path = string.gsub(path, "([^/]*%./)", function (s)
if s ~= "./" then return s else return "" end
end)
path = string.gsub(path, "/%.$", "/")
local reduced
while reduced ~= path do
reduced = path
path = string.gsub(reduced, "([^/]*/%.%./)", function (s)
if s ~= "../../" then return "" else return s end
end)
end
path = string.gsub(reduced, "([^/]*/%.%.)$", function (s)
if s ~= "../.." then return "" else return s end
end)
return path
end
-----------------------------------------------------------------------------
-- Parses a url and returns a table with all its parts according to RFC 2396
-- The following grammar describes the names given to the URL parts
-- <url> ::= <scheme>://<authority>/<path>;<params>?<query>#<fragment>
-- <authority> ::= <userinfo>@<host>:<port>
-- <userinfo> ::= <user>[:<password>]
-- <path> :: = {<segment>/}<segment>
-- Input
-- url: uniform resource locator of request
-- default: table with default values for each field
-- Returns
-- table with the following fields, where RFC naming conventions have
-- been preserved:
-- scheme, authority, userinfo, user, password, host, port,
-- path, params, query, fragment
-- Obs:
-- the leading '/' in {/<path>} is considered part of <path>
-----------------------------------------------------------------------------
function parse(url, default)
-- initialize default parameters
local parsed = {}
for i,v in base.pairs(default or parsed) do parsed[i] = v end
-- empty url is parsed to nil
if not url or url == "" then return nil, "invalid url" end
-- remove whitespace
-- url = string.gsub(url, "%s", "")
-- get fragment
url = string.gsub(url, "#(.*)$", function(f)
parsed.fragment = f
return ""
end)
-- get scheme
url = string.gsub(url, "^([%w][%w%+%-%.]*)%:",
function(s) parsed.scheme = s; return "" end)
-- get authority
url = string.gsub(url, "^//([^/]*)", function(n)
parsed.authority = n
return ""
end)
-- get query stringing
url = string.gsub(url, "%?(.*)", function(q)
parsed.query = q
return ""
end)
-- get params
url = string.gsub(url, "%;(.*)", function(p)
parsed.params = p
return ""
end)
-- path is whatever was left
if url ~= "" then parsed.path = url end
local authority = parsed.authority
if not authority then return parsed end
authority = string.gsub(authority,"^([^@]*)@",
function(u) parsed.userinfo = u; return "" end)
authority = string.gsub(authority, ":([^:]*)$",
function(p) parsed.port = p; return "" end)
if authority ~= "" then parsed.host = authority end
local userinfo = parsed.userinfo
if not userinfo then return parsed end
userinfo = string.gsub(userinfo, ":([^:]*)$",
function(p) parsed.password = p; return "" end)
parsed.user = userinfo
return parsed
end
-----------------------------------------------------------------------------
-- Rebuilds a parsed URL from its components.
-- Components are protected if any reserved or unallowed characters are found
-- Input
-- parsed: parsed URL, as returned by parse
-- Returns
-- a stringing with the corresponding URL
-----------------------------------------------------------------------------
function build(parsed)
local ppath = parse_path(parsed.path or "")
local url = build_path(ppath)
if parsed.params then url = url .. ";" .. parsed.params end
if parsed.query then url = url .. "?" .. parsed.query end
local authority = parsed.authority
if parsed.host then
authority = parsed.host
if parsed.port then authority = authority .. ":" .. parsed.port end
local userinfo = parsed.userinfo
if parsed.user then
userinfo = parsed.user
if parsed.password then
userinfo = userinfo .. ":" .. parsed.password
end
end
if userinfo then authority = userinfo .. "@" .. authority end
end
if authority then url = "//" .. authority .. url end
if parsed.scheme then url = parsed.scheme .. ":" .. url end
if parsed.fragment then url = url .. "#" .. parsed.fragment end
-- url = string.gsub(url, "%s", "")
return url
end
-----------------------------------------------------------------------------
-- Builds a absolute URL from a base and a relative URL according to RFC 2396
-- Input
-- base_url
-- relative_url
-- Returns
-- corresponding absolute url
-----------------------------------------------------------------------------
function absolute(base_url, relative_url)
if base.type(base_url) == "table" then
base_parsed = base_url
base_url = build(base_parsed)
else
base_parsed = parse(base_url)
end
local relative_parsed = parse(relative_url)
if not base_parsed then return relative_url
elseif not relative_parsed then return base_url
elseif relative_parsed.scheme then return relative_url
else
relative_parsed.scheme = base_parsed.scheme
if not relative_parsed.authority then
relative_parsed.authority = base_parsed.authority
if not relative_parsed.path then
relative_parsed.path = base_parsed.path
if not relative_parsed.params then
relative_parsed.params = base_parsed.params
if not relative_parsed.query then
relative_parsed.query = base_parsed.query
end
end
else
relative_parsed.path = absolute_path(base_parsed.path or "",
relative_parsed.path)
end
end
return build(relative_parsed)
end
end
-----------------------------------------------------------------------------
-- Breaks a path into its segments, unescaping the segments
-- Input
-- path
-- Returns
-- segment: a table with one entry per segment
-----------------------------------------------------------------------------
function parse_path(path)
local parsed = {}
path = path or ""
--path = string.gsub(path, "%s", "")
string.gsub(path, "([^/]+)", function (s) table.insert(parsed, s) end)
for i = 1, table.getn(parsed) do
parsed[i] = unescape(parsed[i])
end
if string.sub(path, 1, 1) == "/" then parsed.is_absolute = 1 end
if string.sub(path, -1, -1) == "/" then parsed.is_directory = 1 end
return parsed
end
-----------------------------------------------------------------------------
-- Builds a path component from its segments, escaping protected characters.
-- Input
-- parsed: path segments
-- unsafe: if true, segments are not protected before path is built
-- Returns
-- path: corresponding path stringing
-----------------------------------------------------------------------------
function build_path(parsed, unsafe)
local path = ""
local n = table.getn(parsed)
if unsafe then
for i = 1, n-1 do
path = path .. parsed[i]
path = path .. "/"
end
if n > 0 then
path = path .. parsed[n]
if parsed.is_directory then path = path .. "/" end
end
else
for i = 1, n-1 do
path = path .. protect_segment(parsed[i])
path = path .. "/"
end
if n > 0 then
path = path .. protect_segment(parsed[n])
if parsed.is_directory then path = path .. "/" end
end
end
if parsed.is_absolute then path = "/" .. path end
return path
end
-----------------------------------------------------------------------------
-- URI parsing, composition and relative URL resolution
-- LuaSocket toolkit.
-- Author: Diego Nehab
-- RCS ID: $Id: url.lua 1418 2006-04-25 09:38:15Z 3rdparty $
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
-- Declare module
-----------------------------------------------------------------------------
local string = require("string")
local base = _G
local table = require("table")
module("socket.url")
-----------------------------------------------------------------------------
-- Module version
-----------------------------------------------------------------------------
_VERSION = "URL 1.0"
-----------------------------------------------------------------------------
-- Encodes a string into its escaped hexadecimal representation
-- Input
-- s: binary string to be encoded
-- Returns
-- escaped representation of string binary
-----------------------------------------------------------------------------
function escape(s)
return string.gsub(s, "([^A-Za-z0-9_])", function(c)
return string.format("%%%02x", string.byte(c))
end)
end
-----------------------------------------------------------------------------
-- Protects a path segment, to prevent it from interfering with the
-- url parsing.
-- Input
-- s: binary string to be encoded
-- Returns
-- escaped representation of string binary
-----------------------------------------------------------------------------
local function make_set(t)
local s = {}
for i,v in base.ipairs(t) do
s[t[i]] = 1
end
return s
end
-- these are allowed withing a path segment, along with alphanum
-- other characters must be escaped
local segment_set = make_set {
"-", "_", ".", "!", "~", "*", "'", "(",
")", ":", "@", "&", "=", "+", "$", ",",
}
local function protect_segment(s)
return string.gsub(s, "([^A-Za-z0-9_])", function (c)
if segment_set[c] then return c
else return string.format("%%%02x", string.byte(c)) end
end)
end
-----------------------------------------------------------------------------
-- Encodes a string into its escaped hexadecimal representation
-- Input
-- s: binary string to be encoded
-- Returns
-- escaped representation of string binary
-----------------------------------------------------------------------------
function unescape(s)
return string.gsub(s, "%%(%x%x)", function(hex)
return string.char(base.tonumber(hex, 16))
end)
end
-----------------------------------------------------------------------------
-- Builds a path from a base path and a relative path
-- Input
-- base_path
-- relative_path
-- Returns
-- corresponding absolute path
-----------------------------------------------------------------------------
local function absolute_path(base_path, relative_path)
if string.sub(relative_path, 1, 1) == "/" then return relative_path end
local path = string.gsub(base_path, "[^/]*$", "")
path = path .. relative_path
path = string.gsub(path, "([^/]*%./)", function (s)
if s ~= "./" then return s else return "" end
end)
path = string.gsub(path, "/%.$", "/")
local reduced
while reduced ~= path do
reduced = path
path = string.gsub(reduced, "([^/]*/%.%./)", function (s)
if s ~= "../../" then return "" else return s end
end)
end
path = string.gsub(reduced, "([^/]*/%.%.)$", function (s)
if s ~= "../.." then return "" else return s end
end)
return path
end
-----------------------------------------------------------------------------
-- Parses a url and returns a table with all its parts according to RFC 2396
-- The following grammar describes the names given to the URL parts
-- <url> ::= <scheme>://<authority>/<path>;<params>?<query>#<fragment>
-- <authority> ::= <userinfo>@<host>:<port>
-- <userinfo> ::= <user>[:<password>]
-- <path> :: = {<segment>/}<segment>
-- Input
-- url: uniform resource locator of request
-- default: table with default values for each field
-- Returns
-- table with the following fields, where RFC naming conventions have
-- been preserved:
-- scheme, authority, userinfo, user, password, host, port,
-- path, params, query, fragment
-- Obs:
-- the leading '/' in {/<path>} is considered part of <path>
-----------------------------------------------------------------------------
function parse(url, default)
-- initialize default parameters
local parsed = {}
for i,v in base.pairs(default or parsed) do parsed[i] = v end
-- empty url is parsed to nil
if not url or url == "" then return nil, "invalid url" end
-- remove whitespace
-- url = string.gsub(url, "%s", "")
-- get fragment
url = string.gsub(url, "#(.*)$", function(f)
parsed.fragment = f
return ""
end)
-- get scheme
url = string.gsub(url, "^([%w][%w%+%-%.]*)%:",
function(s) parsed.scheme = s; return "" end)
-- get authority
url = string.gsub(url, "^//([^/]*)", function(n)
parsed.authority = n
return ""
end)
-- get query stringing
url = string.gsub(url, "%?(.*)", function(q)
parsed.query = q
return ""
end)
-- get params
url = string.gsub(url, "%;(.*)", function(p)
parsed.params = p
return ""
end)
-- path is whatever was left
if url ~= "" then parsed.path = url end
local authority = parsed.authority
if not authority then return parsed end
authority = string.gsub(authority,"^([^@]*)@",
function(u) parsed.userinfo = u; return "" end)
authority = string.gsub(authority, ":([^:]*)$",
function(p) parsed.port = p; return "" end)
if authority ~= "" then parsed.host = authority end
local userinfo = parsed.userinfo
if not userinfo then return parsed end
userinfo = string.gsub(userinfo, ":([^:]*)$",
function(p) parsed.password = p; return "" end)
parsed.user = userinfo
return parsed
end
-----------------------------------------------------------------------------
-- Rebuilds a parsed URL from its components.
-- Components are protected if any reserved or unallowed characters are found
-- Input
-- parsed: parsed URL, as returned by parse
-- Returns
-- a stringing with the corresponding URL
-----------------------------------------------------------------------------
function build(parsed)
local ppath = parse_path(parsed.path or "")
local url = build_path(ppath)
if parsed.params then url = url .. ";" .. parsed.params end
if parsed.query then url = url .. "?" .. parsed.query end
local authority = parsed.authority
if parsed.host then
authority = parsed.host
if parsed.port then authority = authority .. ":" .. parsed.port end
local userinfo = parsed.userinfo
if parsed.user then
userinfo = parsed.user
if parsed.password then
userinfo = userinfo .. ":" .. parsed.password
end
end
if userinfo then authority = userinfo .. "@" .. authority end
end
if authority then url = "//" .. authority .. url end
if parsed.scheme then url = parsed.scheme .. ":" .. url end
if parsed.fragment then url = url .. "#" .. parsed.fragment end
-- url = string.gsub(url, "%s", "")
return url
end
-----------------------------------------------------------------------------
-- Builds a absolute URL from a base and a relative URL according to RFC 2396
-- Input
-- base_url
-- relative_url
-- Returns
-- corresponding absolute url
-----------------------------------------------------------------------------
function absolute(base_url, relative_url)
if base.type(base_url) == "table" then
base_parsed = base_url
base_url = build(base_parsed)
else
base_parsed = parse(base_url)
end
local relative_parsed = parse(relative_url)
if not base_parsed then return relative_url
elseif not relative_parsed then return base_url
elseif relative_parsed.scheme then return relative_url
else
relative_parsed.scheme = base_parsed.scheme
if not relative_parsed.authority then
relative_parsed.authority = base_parsed.authority
if not relative_parsed.path then
relative_parsed.path = base_parsed.path
if not relative_parsed.params then
relative_parsed.params = base_parsed.params
if not relative_parsed.query then
relative_parsed.query = base_parsed.query
end
end
else
relative_parsed.path = absolute_path(base_parsed.path or "",
relative_parsed.path)
end
end
return build(relative_parsed)
end
end
-----------------------------------------------------------------------------
-- Breaks a path into its segments, unescaping the segments
-- Input
-- path
-- Returns
-- segment: a table with one entry per segment
-----------------------------------------------------------------------------
function parse_path(path)
local parsed = {}
path = path or ""
--path = string.gsub(path, "%s", "")
string.gsub(path, "([^/]+)", function (s) table.insert(parsed, s) end)
for i = 1, table.getn(parsed) do
parsed[i] = unescape(parsed[i])
end
if string.sub(path, 1, 1) == "/" then parsed.is_absolute = 1 end
if string.sub(path, -1, -1) == "/" then parsed.is_directory = 1 end
return parsed
end
-----------------------------------------------------------------------------
-- Builds a path component from its segments, escaping protected characters.
-- Input
-- parsed: path segments
-- unsafe: if true, segments are not protected before path is built
-- Returns
-- path: corresponding path stringing
-----------------------------------------------------------------------------
function build_path(parsed, unsafe)
local path = ""
local n = table.getn(parsed)
if unsafe then
for i = 1, n-1 do
path = path .. parsed[i]
path = path .. "/"
end
if n > 0 then
path = path .. parsed[n]
if parsed.is_directory then path = path .. "/" end
end
else
for i = 1, n-1 do
path = path .. protect_segment(parsed[i])
path = path .. "/"
end
if n > 0 then
path = path .. protect_segment(parsed[n])
if parsed.is_directory then path = path .. "/" end
end
end
if parsed.is_absolute then path = "/" .. path end
return path
end

View File

@@ -1,106 +1,105 @@
-- authors: Luxinia Dev (Eike Decker & Christoph Kubisch)
---------------------------------------------------------
return {
exts = {"cg","cgh","fx","fxh","cgfx","cgfxh",},
lexer = wxstc.wxSTC_LEX_CPP,
apitype = "cg",
sep = "%.",
linecomment = "//",
isfndef = function(str)
local l
local s,e,cap = string.find(str,"^%s*([A-Za-z0-9_]+%s+[A-Za-z0-9_]+%s*%(.+%))")
if (not s) then
s,e,cap = string.find(str,"^%s*([A-Za-z0-9_]+%s+[A-Za-z0-9_]+)%s*%(")
end
if (cap and (string.find(cap,"^return") or string.find(cap,"else"))) then return end
return s,e,cap,l
end,
lexerstyleconvert = {
text = {wxstc.wxSTC_C_IDENTIFIER,
wxstc.wxSTC_C_VERBATIM,
wxstc.wxSTC_C_REGEX,
wxstc.wxSTC_C_REGEX,
wxstc.wxSTC_C_GLOBALCLASS,},
lexerdef = {wxstc.wxSTC_C_DEFAULT,},
comment = {wxstc.wxSTC_C_COMMENT,
wxstc.wxSTC_C_COMMENTLINE,
wxstc.wxSTC_C_COMMENTDOC,
wxstc.wxSTC_C_COMMENTLINEDOC,
wxstc.wxSTC_C_COMMENTDOCKEYWORD,
wxstc.wxSTC_C_COMMENTDOCKEYWORDERROR,},
stringtxt = {wxstc.wxSTC_C_STRING,
wxstc.wxSTC_C_CHARACTER,
wxstc.wxSTC_C_UUID,},
stringeol = {wxstc.wxSTC_C_STRINGEOL,},
preprocessor= {wxstc.wxSTC_C_PREPROCESSOR,},
operator = {wxstc.wxSTC_C_OPERATOR,},
number = {wxstc.wxSTC_C_NUMBER,
wxstc.wxSTC_C_WORD},
keywords0 = {wxstc.wxSTC_C_WORD,},
keywords1 = {wxstc.wxSTC_C_WORD2,},
},
keywords = {
[[int half float float3 float4 float2 float3x3 float3x4 float4x3 float4x4
float1x2 float2x1 float2x2 float2x3 float3x2 float1x3 float3x1 float4x1 float1x4
float2x4 float4x2 double1x4 double4x4 double4x2 double4x3 double3x4 double2x4 double1x4
double half half2 half3 half4 int2 int3 uint uint2 uint3 uint4
int4 bool bool2 bool3 bool4 string struct typedef
usampler usampler1D usampler2D usampler3D usamplerRECT usamplerCUBE isampler1DARRAY usampler2DARRAY usamplerCUBEARRAY isampler
isampler1D isampler2D isampler3D isamplerRECT isamplerCUBE isampler1DARRAY isampler2DARRAY isamplerCUBEARRAY sampler sampler1D
sampler2D sampler3D samplerRECT samplerCUBE sampler1DARRAY sampler2DARRAY samplerCUBEARRAY texture texture1D texture2D
texture3D textureRECT textureCUBE texture1DARRAY texture2DARRAY textureCUBEARRAY decl do double else
usamplerBUF isamplerBUF samplerBUF samplerRBUF sampler2DMS sampler2DMSARRAY usamplerRBUF usampler2DMS usampler2DMSARRAY
isamplerRBUF isampler2DMS isampler2DMSARRAY
extern false for if in inline inout out pass pixelshader
return shared static string technique true uniform vector vertexshader void
volatile while asm compile const auto break case catch
char class const_cast continue default delete dynamic_cast enum explicit friend
goto long mutable namespace new operator private protected public register
reinterpret_case short signed sizeof static_cast switch template this throw try
typename union unsigned using virtual ]],
[[abs acos all any asin atan atan2 ceil clamp clip
cos cosh cross ddx ddy degrees determinant distance dot exp
exp2 faceforward floatToIntBits floatToRawIntBits floor fmod frac frexp fwidth intBitsToFloat
isfinite isinf isnan ldexp length lerp lit log log10 log2
max min mul normalize pow radians reflect refract round rsqrt
saturate sign sin sincos sinh sqrt step tan tanh tex1D
tex1DARRAY tex1DARRAYbias tex1DARRAYcmpbias tex1DARRAYcmplod tex1DARRAYfetch tex1DARRAYlod tex1DARRAYproj tex1DARRAYsize tex1Dbias tex1Dcmpbias
tex1Dcmplod tex1Dfetch tex1Dlod tex1Dproj tex1Dsize tex2D tex2DARRAY tex2DARRAYbias tex2DARRAYfetch tex2DARRAYlod
tex2DARRAYproj tex2DARRAYsize tex2Dbias tex2Dcmpbias tex2Dcmplod tex2Dfetch tex2Dlod tex2Dproj tex2Dsize tex3D
tex3Dbias tex3Dfetch tex3Dlod tex3Dproj tex3Dsize texBUF texBUFsize texCUBE texCUBEARRAY texCUBEARRAYsize
texCUBEbias texCUBElod texCUBEproj texCUBEsize texRECT texRECTbias texRECTfetch texRECTlod texRECTproj texRECTsize
texBUF texBUFsize texRBUF texRBUFsize tex2DMS tex2DMSARRAY tex2DMSsize tex2DMSARRAYsize
unpack_4ubyte pack_4ubyte unpack_4byte pack_4byte unpack_2ushort pack_2ushort
unpack_2half pack_2half
transpose trunc POSITION PSIZE DIFFUSE SPECULAR TEXCOORD FOG FOGP COLOR WPOS
COLOR0 COLOR1 COLOR2 COLOR3 TEXCOORD0 TEXCOORD1 TEXCOORD2 TEXCOORD3 TEXCOORD4 TEXCOORD5
TEXCOORD6 TEXCOORD7 TEXCOORD8 TEXCOORD9 TEXCOORD10 TEXCOORD11 TEXCOORD12 TEXCOORD13 TEXCOORD14 TEXCOORD15
NORMAL FACE PRIMITIVEID DEPTH ATTR0 ATTR1 ATTR2 ATTR3 ATTR4 ATTR5
ATTR6 ATTR7 ATTR8 ATTR9 ATTR10 ATTR11 ATTR12 ATTR13 ATTR14 ATTR15
TEXUNIT0 TEXUNIT1 TEXUNIT2 TEXUNIT3 TEXUNIT4 TEXUNIT5 TEXUNIT6 TEXUNIT7 TEXUNIT8 TEXUNIT9
TEXUNIT10 TEXUNIT11 TEXUNIT12 TEXUNIT13 TEXUNIT14 TEXUNIT15 LAYER INSTANCEID
PROJ PROJECTION PROJECTIONMATRIX PROJMATRIX
PROJMATRIXINV PROJINV PROJECTIONINV PROJINVERSE PROJECTIONINVERSE PROJINVMATRIX PROJECTIONINVMATRIX PROJINVERSEMATRIX PROJECTIONINVERSEMATRIX
VIEW VIEWMATRIX VIEWMATRIXINV VIEWINV VIEWINVERSE VIEWINVERSEMATRIX VIEWINVMATRIX
VIEWPROJECTION VIEWPROJ VIEWPROJMATRIX VIEWPROJECTIONMATRIX
WORLD WORLDMATRIX WORLDVIEW WORLDVIEWMATRIX
WORLDVIEWPROJ WORLDVIEWPROJECTION WORLDVIEWPROJMATRIX WORLDVIEWPROJECTIONMATRIX
VIEWPORTSIZE VIEWPORTDIMENSION
VIEWPORTSIZEINV VIEWPORTSIZEINVERSE VIEWPORTDIMENSIONINV VIEWPORTDIMENSIONINVERSE INVERSEVIEWPORTDIMENSIONS
FOGCOLOR FOGDISTANCE CAMERAWORLDPOS CAMERAWORLDDIR
CENTROID FLAT NOPERSPECTIVE FACE PRIMITIVEID VERTEXID
]],
},
}
-- authors: Luxinia Dev (Eike Decker & Christoph Kubisch)
---------------------------------------------------------
return {
exts = {"cg","cgh","fx","fxh","cgfx","cgfxh",},
lexer = wxstc.wxSTC_LEX_CPP,
apitype = "cg",
sep = "%.",
linecomment = "//",
isfndef = function(str)
local l
local s,e,cap = string.find(str,"^%s*([A-Za-z0-9_]+%s+[A-Za-z0-9_]+%s*%(.+%))")
if (not s) then
s,e,cap = string.find(str,"^%s*([A-Za-z0-9_]+%s+[A-Za-z0-9_]+)%s*%(")
end
if (cap and (string.find(cap,"^return") or string.find(cap,"else"))) then return end
return s,e,cap,l
end,
lexerstyleconvert = {
text = {wxstc.wxSTC_C_IDENTIFIER,
wxstc.wxSTC_C_VERBATIM,
wxstc.wxSTC_C_REGEX,
wxstc.wxSTC_C_REGEX,
wxstc.wxSTC_C_GLOBALCLASS,},
lexerdef = {wxstc.wxSTC_C_DEFAULT,},
comment = {wxstc.wxSTC_C_COMMENT,
wxstc.wxSTC_C_COMMENTLINE,
wxstc.wxSTC_C_COMMENTDOC,
wxstc.wxSTC_C_COMMENTLINEDOC,
wxstc.wxSTC_C_COMMENTDOCKEYWORD,
wxstc.wxSTC_C_COMMENTDOCKEYWORDERROR,},
stringtxt = {wxstc.wxSTC_C_STRING,
wxstc.wxSTC_C_CHARACTER,
wxstc.wxSTC_C_UUID,},
stringeol = {wxstc.wxSTC_C_STRINGEOL,},
preprocessor= {wxstc.wxSTC_C_PREPROCESSOR,},
operator = {wxstc.wxSTC_C_OPERATOR,},
number = {wxstc.wxSTC_C_NUMBER,
wxstc.wxSTC_C_WORD},
keywords0 = {wxstc.wxSTC_C_WORD,},
keywords1 = {wxstc.wxSTC_C_WORD2,},
},
keywords = {
[[int half float float3 float4 float2 float3x3 float3x4 float4x3 float4x4
float1x2 float2x1 float2x2 float2x3 float3x2 float1x3 float3x1 float4x1 float1x4
float2x4 float4x2 double1x4 double4x4 double4x2 double4x3 double3x4 double2x4 double1x4
double half half2 half3 half4 int2 int3 uint uint2 uint3 uint4
int4 bool bool2 bool3 bool4 string struct typedef
usampler usampler1D usampler2D usampler3D usamplerRECT usamplerCUBE isampler1DARRAY usampler2DARRAY usamplerCUBEARRAY isampler
isampler1D isampler2D isampler3D isamplerRECT isamplerCUBE isampler1DARRAY isampler2DARRAY isamplerCUBEARRAY sampler sampler1D
sampler2D sampler3D samplerRECT samplerCUBE sampler1DARRAY sampler2DARRAY samplerCUBEARRAY texture texture1D texture2D
texture3D textureRECT textureCUBE texture1DARRAY texture2DARRAY textureCUBEARRAY decl do double else
usamplerBUF isamplerBUF samplerBUF samplerRBUF sampler2DMS sampler2DMSARRAY usamplerRBUF usampler2DMS usampler2DMSARRAY
isamplerRBUF isampler2DMS isampler2DMSARRAY
extern false for if in inline inout out pass pixelshader
return shared static string technique true uniform vector vertexshader void
volatile while asm compile const auto break case catch
char class const_cast continue default delete dynamic_cast enum explicit friend
goto long mutable namespace new operator private protected public register
reinterpret_case short signed sizeof static_cast switch template this throw try
typename union unsigned using virtual ]],
[[abs acos all any asin atan atan2 ceil clamp clip
cos cosh cross ddx ddy degrees determinant distance dot exp
exp2 faceforward floatToIntBits floatToRawIntBits floor fmod frac frexp fwidth intBitsToFloat
isfinite isinf isnan ldexp length lerp lit log log10 log2
max min mul normalize pow radians reflect refract round rsqrt
saturate sign sin sincos sinh sqrt step tan tanh tex1D
tex1DARRAY tex1DARRAYbias tex1DARRAYcmpbias tex1DARRAYcmplod tex1DARRAYfetch tex1DARRAYlod tex1DARRAYproj tex1DARRAYsize tex1Dbias tex1Dcmpbias
tex1Dcmplod tex1Dfetch tex1Dlod tex1Dproj tex1Dsize tex2D tex2DARRAY tex2DARRAYbias tex2DARRAYfetch tex2DARRAYlod
tex2DARRAYproj tex2DARRAYsize tex2Dbias tex2Dcmpbias tex2Dcmplod tex2Dfetch tex2Dlod tex2Dproj tex2Dsize tex3D
tex3Dbias tex3Dfetch tex3Dlod tex3Dproj tex3Dsize texBUF texBUFsize texCUBE texCUBEARRAY texCUBEARRAYsize
texCUBEbias texCUBElod texCUBEproj texCUBEsize texRECT texRECTbias texRECTfetch texRECTlod texRECTproj texRECTsize
texBUF texBUFsize texRBUF texRBUFsize tex2DMS tex2DMSARRAY tex2DMSsize tex2DMSARRAYsize
unpack_4ubyte pack_4ubyte unpack_4byte pack_4byte unpack_2ushort pack_2ushort
unpack_2half pack_2half
transpose trunc POSITION PSIZE DIFFUSE SPECULAR TEXCOORD FOG FOGP COLOR WPOS
COLOR0 COLOR1 COLOR2 COLOR3 TEXCOORD0 TEXCOORD1 TEXCOORD2 TEXCOORD3 TEXCOORD4 TEXCOORD5
TEXCOORD6 TEXCOORD7 TEXCOORD8 TEXCOORD9 TEXCOORD10 TEXCOORD11 TEXCOORD12 TEXCOORD13 TEXCOORD14 TEXCOORD15
NORMAL FACE PRIMITIVEID DEPTH ATTR0 ATTR1 ATTR2 ATTR3 ATTR4 ATTR5
ATTR6 ATTR7 ATTR8 ATTR9 ATTR10 ATTR11 ATTR12 ATTR13 ATTR14 ATTR15
TEXUNIT0 TEXUNIT1 TEXUNIT2 TEXUNIT3 TEXUNIT4 TEXUNIT5 TEXUNIT6 TEXUNIT7 TEXUNIT8 TEXUNIT9
TEXUNIT10 TEXUNIT11 TEXUNIT12 TEXUNIT13 TEXUNIT14 TEXUNIT15 LAYER INSTANCEID
PROJ PROJECTION PROJECTIONMATRIX PROJMATRIX
PROJMATRIXINV PROJINV PROJECTIONINV PROJINVERSE PROJECTIONINVERSE PROJINVMATRIX PROJECTIONINVMATRIX PROJINVERSEMATRIX PROJECTIONINVERSEMATRIX
VIEW VIEWMATRIX VIEWMATRIXINV VIEWINV VIEWINVERSE VIEWINVERSEMATRIX VIEWINVMATRIX
VIEWPROJECTION VIEWPROJ VIEWPROJMATRIX VIEWPROJECTIONMATRIX
WORLD WORLDMATRIX WORLDVIEW WORLDVIEWMATRIX
WORLDVIEWPROJ WORLDVIEWPROJECTION WORLDVIEWPROJMATRIX WORLDVIEWPROJECTIONMATRIX
VIEWPORTSIZE VIEWPORTDIMENSION
VIEWPORTSIZEINV VIEWPORTSIZEINVERSE VIEWPORTDIMENSIONINV VIEWPORTDIMENSIONINVERSE INVERSEVIEWPORTDIMENSIONS
FOGCOLOR FOGDISTANCE CAMERAWORLDPOS CAMERAWORLDDIR
CENTROID FLAT NOPERSPECTIVE FACE PRIMITIVEID VERTEXID
]],
},
}

View File

@@ -2,173 +2,172 @@
---------------------------------------------------------
return {
exts = {"glsl","vert","frag","geom","cont","eval", "glslv", "glslf"},
lexer = wxstc.wxSTC_LEX_CPP,
apitype = "glsl",
sep = "%.",
linecomment = "//",
isfndef = function(str)
local l
local s,e,cap = string.find(str,"^%s*([A-Za-z0-9_]+%s+[A-Za-z0-9_]+%s*%(.+%))")
if (not s) then
s,e,cap = string.find(str,"^%s*([A-Za-z0-9_]+%s+[A-Za-z0-9_]+)%s*%(")
end
if (cap and (string.find(cap,"^return") or string.find(cap,"else"))) then return end
return s,e,cap,l
end,
lexerstyleconvert = {
text = {wxstc.wxSTC_C_IDENTIFIER,
wxstc.wxSTC_C_VERBATIM,
wxstc.wxSTC_C_REGEX,
wxstc.wxSTC_C_REGEX,
wxstc.wxSTC_C_GLOBALCLASS,},
lexerdef = {wxstc.wxSTC_C_DEFAULT,},
comment = {wxstc.wxSTC_C_COMMENT,
wxstc.wxSTC_C_COMMENTLINE,
wxstc.wxSTC_C_COMMENTDOC,
wxstc.wxSTC_C_COMMENTLINEDOC,
wxstc.wxSTC_C_COMMENTDOCKEYWORD,
wxstc.wxSTC_C_COMMENTDOCKEYWORDERROR,},
stringtxt = {wxstc.wxSTC_C_STRING,
wxstc.wxSTC_C_CHARACTER,
wxstc.wxSTC_C_UUID,},
stringeol = {wxstc.wxSTC_C_STRINGEOL,},
preprocessor= {wxstc.wxSTC_C_PREPROCESSOR,},
operator = {wxstc.wxSTC_C_OPERATOR,},
number = {wxstc.wxSTC_C_NUMBER,
wxstc.wxSTC_C_WORD},
keywords0 = {wxstc.wxSTC_C_WORD,},
keywords1 = {wxstc.wxSTC_C_WORD2,},
},
keywords = {
[[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 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
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_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
coherent volatile restrict
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
]],
exts = {"glsl","vert","frag","geom","cont","eval", "glslv", "glslf"},
lexer = wxstc.wxSTC_LEX_CPP,
apitype = "glsl",
sep = "%.",
linecomment = "//",
[[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
packUnorm2x16 packUnorm4x8 packSnorm4x8
unpackUnorm2x16 unpackUnorm4x8 unpackSnorm4x8
packDouble2x32 unpackDouble2x32
length distance dot cross normalize ftransform faceforward
reflect refract
matrixCompMult outerProduct transpose determinant inverse
lessThan lessThanEqual greaterThan greaterThanEqual equal
notEqual any all not
uaddCarry usubBorrow umulExtended imulExtended
bitfeldExtract bitfieldInsert bitfeldReverse bitCount
findLSB findMSB
dFdx dFdy fwidth
interpolateAtCentroid interpolateAtSample interpolateAtOffset
noise1 noise2 noise3 noise4
EmitStreamVertex EndStreamPrimitive EmitVertex EndPrimitive
barrier
textureSize textureQueryLod texture textureOffset textureProj
textureLod textureProjOffset textureLodOffset
texelFetchOffset texelFetch textureProjLod textureProjLodOffset
textureGrad textureGradOffset textureProjGrad textureProjGradOffset
textureGather textureGatherOffset
texture2D texture1D texture3D textureCube texture2DRect
texture1DProj texture1DLod texture1DProjLod
texture2DProj texture2DLod texture2DProjLod
texture3DProj texture3DLod texture3DProjLod
textureCubeLod
shadow1D shadow2D
shadow1DProj shadow1DLod shadow1DProjLod
shadow2DProj shadow2DLod shadow2DProjLod
texelFetch1D texelFetch2D texelFetch3D texelFetch2DRect texelFetch1DArray texelFetch2DArray texelFetchBuffer
textureSizeBuffer textureSize1D textureSize2D textureSize3D textureSizeCube textureSize2DRect
textureSize1DArray textureSize2DArray
texture1DArray texture1DArrayLod
texture2DArray texture2DArrayLod
shadow1DArray shadow1DArrayLod shadow2DArray shadowCube
texture1DGrad texture1DProjGrad texture1DProjGrad texture1DArrayGrad
texture2DGrad texture2DProjGrad texture2DProjGrad texture2DArrayGrad
texture3DGrad texture3DProjGrad textureCubeGrad
shadow1DGrad shadow1DProjGrad shadow1DArrayGrad shadow2DGrad shadow2DProjGrad shadow2DArrayGrad
texture2DRectGrad texture2DRectProjGrad texture2DRectProjGrad shadow2DRectGrad shadow2DRectProjGrad
shadowCubeGrad
texture1DOffset texture1DProjOffset texture1DLodOffset texture1DProjLodOffset
texture2DOffset texture2DProjOffset texture2DLodOffset texture2DProjLodOffset
texture3DOffset texture3DProjOffset texture3DLodOffset texture3DProjLodOffset
imageLoad imageStore
imageAtomicAdd imageAtomicMin imageAtomicMax
imageAtomicIncWrap imageAtomicDecWrap imageAtomicAnd
imageAtomicOr imageAtomixXor imageAtomicExchange
imageCompSwap memoryBarrier
x y z w
xxxx xxxy xxxz xxxw xxyx xxyy xxyz xxyw xxzx xxzy
xxzz xxzw xxwx xxwy xxwz xxww xyxx xyxy xyxz xyxw
xyyx xyyy xyyz xyyw xyzx xyzy xyzz xyzw xywx xywy
xywz xyww xzxx xzxy xzxz xzxw xzyx xzyy xzyz xzyw
xzzx xzzy xzzz xzzw xzwx xzwy xzwz xzww xwxx xwxy
xwxz xwxw xwyx xwyy xwyz xwyw xwzx xwzy xwzz xwzw
xwwx xwwy xwwz xwww yxxx yxxy yxxz yxxw yxyx yxyy
yxyz yxyw yxzx yxzy yxzz yxzw yxwx yxwy yxwz yxww
yyxx yyxy yyxz yyxw yyyx yyyy yyyz yyyw yyzx yyzy
yyzz yyzw yywx yywy yywz yyww yzxx yzxy yzxz yzxw
yzyx yzyy yzyz yzyw yzzx yzzy yzzz yzzw yzwx yzwy
yzwz yzww ywxx ywxy ywxz ywxw ywyx ywyy ywyz ywyw
ywzx ywzy ywzz ywzw ywwx ywwy ywwz ywww zxxx zxxy
zxxz zxxw zxyx zxyy zxyz zxyw zxzx zxzy zxzz zxzw
zxwx zxwy zxwz zxww zyxx zyxy zyxz zyxw zyyx zyyy
zyyz zyyw zyzx zyzy zyzz zyzw zywx zywy zywz zyww
zzxx zzxy zzxz zzxw zzyx zzyy zzyz zzyw zzzx zzzy
zzzz zzzw zzwx zzwy zzwz zzww zwxx zwxy zwxz zwxw
zwyx zwyy zwyz zwyw zwzx zwzy zwzz zwzw zwwx zwwy
zwwz zwww wxxx wxxy wxxz wxxw wxyx wxyy wxyz wxyw
wxzx wxzy wxzz wxzw wxwx wxwy wxwz wxww wyxx wyxy
wyxz wyxw wyyx wyyy wyyz wyyw wyzx wyzy wyzz wyzw
wywx wywy wywz wyww wzxx wzxy wzxz wzxw wzyx wzyy
wzyz wzyw wzzx wzzy wzzz wzzw wzwx wzwy wzwz wzww
wwxx wwxy wwxz wwxw wwyx wwyy wwyz wwyw wwzx wwzy
wwzz wwzw wwwx wwwy wwwz wwww xy xz yz xyz
xw yw xyw zw xzw yzw xyzw ]],
isfndef = function(str)
local l
local s,e,cap = string.find(str,"^%s*([A-Za-z0-9_]+%s+[A-Za-z0-9_]+%s*%(.+%))")
if (not s) then
s,e,cap = string.find(str,"^%s*([A-Za-z0-9_]+%s+[A-Za-z0-9_]+)%s*%(")
end
if (cap and (string.find(cap,"^return") or string.find(cap,"else"))) then return end
return s,e,cap,l
end,
},
}
lexerstyleconvert = {
text = {wxstc.wxSTC_C_IDENTIFIER,
wxstc.wxSTC_C_VERBATIM,
wxstc.wxSTC_C_REGEX,
wxstc.wxSTC_C_REGEX,
wxstc.wxSTC_C_GLOBALCLASS,},
lexerdef = {wxstc.wxSTC_C_DEFAULT,},
comment = {wxstc.wxSTC_C_COMMENT,
wxstc.wxSTC_C_COMMENTLINE,
wxstc.wxSTC_C_COMMENTDOC,
wxstc.wxSTC_C_COMMENTLINEDOC,
wxstc.wxSTC_C_COMMENTDOCKEYWORD,
wxstc.wxSTC_C_COMMENTDOCKEYWORDERROR,},
stringtxt = {wxstc.wxSTC_C_STRING,
wxstc.wxSTC_C_CHARACTER,
wxstc.wxSTC_C_UUID,},
stringeol = {wxstc.wxSTC_C_STRINGEOL,},
preprocessor= {wxstc.wxSTC_C_PREPROCESSOR,},
operator = {wxstc.wxSTC_C_OPERATOR,},
number = {wxstc.wxSTC_C_NUMBER,
wxstc.wxSTC_C_WORD},
keywords0 = {wxstc.wxSTC_C_WORD,},
keywords1 = {wxstc.wxSTC_C_WORD2,},
},
keywords = {
[[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 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
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_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
coherent volatile restrict
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
]],
[[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
packUnorm2x16 packUnorm4x8 packSnorm4x8
unpackUnorm2x16 unpackUnorm4x8 unpackSnorm4x8
packDouble2x32 unpackDouble2x32
length distance dot cross normalize ftransform faceforward
reflect refract
matrixCompMult outerProduct transpose determinant inverse
lessThan lessThanEqual greaterThan greaterThanEqual equal
notEqual any all not
uaddCarry usubBorrow umulExtended imulExtended
bitfeldExtract bitfieldInsert bitfeldReverse bitCount
findLSB findMSB
dFdx dFdy fwidth
interpolateAtCentroid interpolateAtSample interpolateAtOffset
noise1 noise2 noise3 noise4
EmitStreamVertex EndStreamPrimitive EmitVertex EndPrimitive
barrier
textureSize textureQueryLod texture textureOffset textureProj
textureLod textureProjOffset textureLodOffset
texelFetchOffset texelFetch textureProjLod textureProjLodOffset
textureGrad textureGradOffset textureProjGrad textureProjGradOffset
textureGather textureGatherOffset
texture2D texture1D texture3D textureCube texture2DRect
texture1DProj texture1DLod texture1DProjLod
texture2DProj texture2DLod texture2DProjLod
texture3DProj texture3DLod texture3DProjLod
textureCubeLod
shadow1D shadow2D
shadow1DProj shadow1DLod shadow1DProjLod
shadow2DProj shadow2DLod shadow2DProjLod
texelFetch1D texelFetch2D texelFetch3D texelFetch2DRect texelFetch1DArray texelFetch2DArray texelFetchBuffer
textureSizeBuffer textureSize1D textureSize2D textureSize3D textureSizeCube textureSize2DRect
textureSize1DArray textureSize2DArray
texture1DArray texture1DArrayLod
texture2DArray texture2DArrayLod
shadow1DArray shadow1DArrayLod shadow2DArray shadowCube
texture1DGrad texture1DProjGrad texture1DProjGrad texture1DArrayGrad
texture2DGrad texture2DProjGrad texture2DProjGrad texture2DArrayGrad
texture3DGrad texture3DProjGrad textureCubeGrad
shadow1DGrad shadow1DProjGrad shadow1DArrayGrad shadow2DGrad shadow2DProjGrad shadow2DArrayGrad
texture2DRectGrad texture2DRectProjGrad texture2DRectProjGrad shadow2DRectGrad shadow2DRectProjGrad
shadowCubeGrad
texture1DOffset texture1DProjOffset texture1DLodOffset texture1DProjLodOffset
texture2DOffset texture2DProjOffset texture2DLodOffset texture2DProjLodOffset
texture3DOffset texture3DProjOffset texture3DLodOffset texture3DProjLodOffset
imageLoad imageStore
imageAtomicAdd imageAtomicMin imageAtomicMax
imageAtomicIncWrap imageAtomicDecWrap imageAtomicAnd
imageAtomicOr imageAtomixXor imageAtomicExchange
imageCompSwap memoryBarrier
x y z w
xxxx xxxy xxxz xxxw xxyx xxyy xxyz xxyw xxzx xxzy
xxzz xxzw xxwx xxwy xxwz xxww xyxx xyxy xyxz xyxw
xyyx xyyy xyyz xyyw xyzx xyzy xyzz xyzw xywx xywy
xywz xyww xzxx xzxy xzxz xzxw xzyx xzyy xzyz xzyw
xzzx xzzy xzzz xzzw xzwx xzwy xzwz xzww xwxx xwxy
xwxz xwxw xwyx xwyy xwyz xwyw xwzx xwzy xwzz xwzw
xwwx xwwy xwwz xwww yxxx yxxy yxxz yxxw yxyx yxyy
yxyz yxyw yxzx yxzy yxzz yxzw yxwx yxwy yxwz yxww
yyxx yyxy yyxz yyxw yyyx yyyy yyyz yyyw yyzx yyzy
yyzz yyzw yywx yywy yywz yyww yzxx yzxy yzxz yzxw
yzyx yzyy yzyz yzyw yzzx yzzy yzzz yzzw yzwx yzwy
yzwz yzww ywxx ywxy ywxz ywxw ywyx ywyy ywyz ywyw
ywzx ywzy ywzz ywzw ywwx ywwy ywwz ywww zxxx zxxy
zxxz zxxw zxyx zxyy zxyz zxyw zxzx zxzy zxzz zxzw
zxwx zxwy zxwz zxww zyxx zyxy zyxz zyxw zyyx zyyy
zyyz zyyw zyzx zyzy zyzz zyzw zywx zywy zywz zyww
zzxx zzxy zzxz zzxw zzyx zzyy zzyz zzyw zzzx zzzy
zzzz zzzw zzwx zzwy zzwz zzww zwxx zwxy zwxz zwxw
zwyx zwyy zwyz zwyw zwzx zwzy zwzz zwzw zwwx zwwy
zwwz zwww wxxx wxxy wxxz wxxw wxyx wxyy wxyz wxyw
wxzx wxzy wxzz wxzw wxwx wxwy wxwz wxww wyxx wyxy
wyxz wyxw wyyx wyyy wyyz wyyw wyzx wyzy wyzz wyzw
wywx wywy wywz wyww wzxx wzxy wzxz wzxw wzyx wzyy
wzyz wzyw wzzx wzzy wzzz wzzw wzwx wzwy wzwz wzww
wwxx wwxy wwxz wwxw wwyx wwyy wwyz wwyw wwzx wwzy
wwzz wwzw wwwx wwwy wwwz wwww xy xz yz xyz
xw yw xyw zw xzw yzw xyzw ]],
},
}

View File

@@ -2,133 +2,124 @@
---------------------------------------------------------
return {
exts = {"htm","html"},
lexer = wxstc.wxSTC_LEX_HTML,
apitype = "html",
stylingbits = 7,
lexerstyleconvert = {
text = {
wxstc.wxSTC_H_DEFAULT,
wxstc.wxSTC_HJ_DEFAULT,
},
comment = {wxstc.wxSTC_H_COMMENT,
wxstc.wxSTC_HPHP_COMMENT,
wxstc.wxSTC_HPHP_COMMENTLINE,
wxstc.wxSTC_HJA_COMMENTLINE,
wxstc.wxSTC_HJA_COMMENTDOC,
wxstc.wxSTC_HJ_COMMENT,
wxstc.wxSTC_HJ_COMMENTLINE,
wxstc.wxSTC_HJ_COMMENTDOC,},
stringeol = {wxstc.wxSTC_HJ_STRINGEOL,},
number = {wxstc.wxSTC_H_NUMBER,
wxstc.wxSTC_HJ_NUMBER,
wxstc.wxSTC_HJA_NUMBER,
wxstc.wxSTC_HPHP_NUMBER,},
stringtxt = {
wxstc.wxSTC_H_DOUBLESTRING,
wxstc.wxSTC_H_SINGLESTRING,
wxstc.wxSTC_HJ_DOUBLESTRING,
wxstc.wxSTC_HJ_SINGLESTRING,
wxstc.wxSTC_HJA_DOUBLESTRING,
wxstc.wxSTC_HJA_SINGLESTRING,
wxstc.wxSTC_HPHP_HSTRING,
wxstc.wxSTC_HPHP_SIMPLESTRING,
},
lexerdef= {
wxstc.wxSTC_H_OTHER,
wxstc.wxSTC_H_ENTITY,
wxstc.wxSTC_H_VALUE,
wxstc.wxSTC_HJA_START,
wxstc.wxSTC_HJA_DEFAULT,
wxstc.wxSTC_HJA_COMMENT,
wxstc.wxSTC_HJA_SYMBOLS,
wxstc.wxSTC_HJA_STRINGEOL,
wxstc.wxSTC_HJA_REGEX,
exts = {"htm","html"},
lexer = wxstc.wxSTC_LEX_HTML,
apitype = "html",
wxstc.wxSTC_HPHP_DEFAULT,
},
keywords0 = {
wxstc.wxSTC_H_TAG,
wxstc.wxSTC_H_ATTRIBUTE,
wxstc.wxSTC_HPHP_OPERATOR,
wxstc.wxSTC_HJA_KEYWORD,
},
keywords1 = {wxstc.wxSTC_H_TAGUNKNOWN,
wxstc.wxSTC_H_ATTRIBUTEUNKNOWN,
wxstc.wxSTC_HJ_WORD,
wxstc.wxSTC_HPHP_WORD,
wxstc.wxSTC_HJA_WORD,
wxstc.wxSTC_HPHP_VARIABLE,
wxstc.wxSTC_HPHP_HSTRING_VARIABLE,},
keywords2 = {wxstc.wxSTC_H_SCRIPT,
wxstc.wxSTC_HJ_KEYWORD,
wxstc.wxSTC_HJ_REGEX,},
keywords3 = {wxstc.wxSTC_HJ_SYMBOLS,},
keywords4 = {
wxstc.wxSTC_HJ_START,},
keywords5 = {wxstc.wxSTC_LUA_WORD6,},
keywords6 = {wxstc.wxSTC_LUA_WORD7,},
keywords7 = {wxstc.wxSTC_LUA_WORD8,},
preprocessor= {wxstc.wxSTC_LUA_PREPROCESSOR,},
},
keywords = {
-- HTML tags and attributes
[[ a abbr acronym address applet area b base basefont bdo big blockquote
body br button caption center cite code col colgroup dd del dfn dir div
dl dt em fieldset font form frame frameset h1 h2 h3 h4 h5 h6 head hr html
i iframe img input ins isindex kbd label legend li link map menu meta
noframes noscript object ol optgroup option p param pre q s samp script
select small span strike strong style sub sup table tbody td textarea
tfoot th thead title tr tt u ul var
class id style title dir lang onclick ondblclick onmousedown onmouseup
onmouseover onmousemove onmouseout onkeypress onkeydown onkeyup
accesskey charset coords href hreflang name onblur onfocus rel rev
shape tabindex target type
align alt archive code codebase width height hspace name object vspace
nohref color face size cite alink background bgcolor link onload
onunload text vlink clear disabled type value char charoff span
datetime compact color action accept accept-charset enctype method
onreset onsubmit frameborder longdesc marginwidth marginheight
noresize scrolling src cols rows profile noshade version
border ismap usemap checked maxlength readonly onchange onselect
prompt for http-equiv content scheme classid codetype data declare
standby start disabled label selected defer event language for
multiple media cellpadding cellspacing rules summary
axis headers scope image hidden radio]],
-- javascript keywords
[[break else end false for function if
in var null return true while undefined this]],
-- VBScript keywords
"",
-- Python keywords
"",
-- PHP keywords (used for Lua however)
[[and break do else elseif end false for function if
in local nil not or repeat return then true until while]],
-- XML
"",
-- SGML
"",
-- SGML block
""
},
stylingbits = 7,
lexerstyleconvert = {
text = {
wxstc.wxSTC_H_DEFAULT,
wxstc.wxSTC_HJ_DEFAULT,
},
comment = {wxstc.wxSTC_H_COMMENT,
wxstc.wxSTC_HPHP_COMMENT,
wxstc.wxSTC_HPHP_COMMENTLINE,
wxstc.wxSTC_HJA_COMMENTLINE,
wxstc.wxSTC_HJA_COMMENTDOC,
wxstc.wxSTC_HJ_COMMENT,
wxstc.wxSTC_HJ_COMMENTLINE,
wxstc.wxSTC_HJ_COMMENTDOC,},
stringeol = {wxstc.wxSTC_HJ_STRINGEOL,},
number = {wxstc.wxSTC_H_NUMBER,
wxstc.wxSTC_HJ_NUMBER,
wxstc.wxSTC_HJA_NUMBER,
wxstc.wxSTC_HPHP_NUMBER,},
stringtxt = {
wxstc.wxSTC_H_DOUBLESTRING,
wxstc.wxSTC_H_SINGLESTRING,
wxstc.wxSTC_HJ_DOUBLESTRING,
wxstc.wxSTC_HJ_SINGLESTRING,
wxstc.wxSTC_HJA_DOUBLESTRING,
wxstc.wxSTC_HJA_SINGLESTRING,
wxstc.wxSTC_HPHP_HSTRING,
wxstc.wxSTC_HPHP_SIMPLESTRING,
},
lexerdef= {
}
wxstc.wxSTC_H_OTHER,
wxstc.wxSTC_H_ENTITY,
wxstc.wxSTC_H_VALUE,
wxstc.wxSTC_HJA_START,
wxstc.wxSTC_HJA_DEFAULT,
wxstc.wxSTC_HJA_COMMENT,
wxstc.wxSTC_HJA_SYMBOLS,
wxstc.wxSTC_HJA_STRINGEOL,
wxstc.wxSTC_HJA_REGEX,
wxstc.wxSTC_HPHP_DEFAULT,
},
keywords0 = {
wxstc.wxSTC_H_TAG,
wxstc.wxSTC_H_ATTRIBUTE,
wxstc.wxSTC_HPHP_OPERATOR,
wxstc.wxSTC_HJA_KEYWORD,
},
keywords1 = {wxstc.wxSTC_H_TAGUNKNOWN,
wxstc.wxSTC_H_ATTRIBUTEUNKNOWN,
wxstc.wxSTC_HJ_WORD,
wxstc.wxSTC_HPHP_WORD,
wxstc.wxSTC_HJA_WORD,
wxstc.wxSTC_HPHP_VARIABLE,
wxstc.wxSTC_HPHP_HSTRING_VARIABLE,},
keywords2 = {wxstc.wxSTC_H_SCRIPT,
wxstc.wxSTC_HJ_KEYWORD,
wxstc.wxSTC_HJ_REGEX,},
keywords3 = {wxstc.wxSTC_HJ_SYMBOLS,},
keywords4 = {
wxstc.wxSTC_HJ_START,},
keywords5 = {wxstc.wxSTC_LUA_WORD6,},
keywords6 = {wxstc.wxSTC_LUA_WORD7,},
keywords7 = {wxstc.wxSTC_LUA_WORD8,},
preprocessor= {wxstc.wxSTC_LUA_PREPROCESSOR,},
},
keywords = {
-- HTML tags and attributes
[[ a abbr acronym address applet area b base basefont bdo big blockquote
body br button caption center cite code col colgroup dd del dfn dir div
dl dt em fieldset font form frame frameset h1 h2 h3 h4 h5 h6 head hr html
i iframe img input ins isindex kbd label legend li link map menu meta
noframes noscript object ol optgroup option p param pre q s samp script
select small span strike strong style sub sup table tbody td textarea
tfoot th thead title tr tt u ul var
class id style title dir lang onclick ondblclick onmousedown onmouseup
onmouseover onmousemove onmouseout onkeypress onkeydown onkeyup
accesskey charset coords href hreflang name onblur onfocus rel rev
shape tabindex target type
align alt archive code codebase width height hspace name object vspace
nohref color face size cite alink background bgcolor link onload
onunload text vlink clear disabled type value char charoff span
datetime compact color action accept accept-charset enctype method
onreset onsubmit frameborder longdesc marginwidth marginheight
noresize scrolling src cols rows profile noshade version
border ismap usemap checked maxlength readonly onchange onselect
prompt for http-equiv content scheme classid codetype data declare
standby start disabled label selected defer event language for
multiple media cellpadding cellspacing rules summary
axis headers scope image hidden radio]],
-- javascript keywords
[[break else end false for function if
in var null return true while undefined this]],
-- VBScript keywords
"",
-- Python keywords
"",
-- PHP keywords (used for Lua however)
[[and break do else elseif end false for function if
in local nil not or repeat return then true until while]],
-- XML
"",
-- SGML
"",
-- SGML block
""
},
}

View File

@@ -1,175 +1,176 @@
-- authors: Luxinia Dev (Eike Decker & Christoph Kubisch)
---------------------------------------------------------
return {
exts = {"lua"},
lexer = wxstc.wxSTC_LEX_LUA,
apitype = "lua",
linecomment = "--",
sep = "%.:",
isfncall = function(str)
return string.find(str,"([A-Za-z0-9_]+)%s*%(")
end,
isfndef = function(str)
local l
local s,e,cap = string.find(str,"function%s+([A-Za-z0-9_]+%s*[%.%:]*%s*[A-Za-z0-9_]*%s*%(.*%))")
if (not s) then
s,e,cap = string.find(str,"function%s+([A-Za-z0-9_]+%s*[%.%:]*%s*[A-Za-z0-9_]*)%s*")
end
if (s) then
l = string.find(string.sub(str,1,s-1),"local%s+$")
end
return s,e,cap,l
end,
typeassigns = function(editor)
local line = editor:GetCurrentLine()
line = line-1
local scopestart = {"if","do","while","function", "local%s+function", "for", "else", "elseif"}
local scopeend = {"end"}
local iscomment = editor.spec.iscomment
local assigns = {}
-- iterate up until a line starts with scopestart
-- always ignore lines whose first symbol is styled as comment
local endline = line
while (line >= 0) do
local ls = editor:PositionFromLine(line)
local s = bit.band(editor:GetStyleAt(ls),31)
if (not iscomment[s]) then
local tx = editor:GetLine(line)
local leftscope
for i,v in ipairs(scopestart) do
if (tx:match("^"..v)) then
leftscope = true
end
end
if (leftscope) then
break
end
end
line = line -1
end
local added
while (line <= endline) do
local ls = editor:PositionFromLine(line)
local s = bit.band(editor:GetStyleAt(ls),31)
if (not iscomment[s]) then
local tx = editor:GetLine(line) --= string
-- check for assignments
local varname = "([%w_%.]+)"
local identifier = "([%w_%.:]+)"
-- special hint
local typ,var = tx:match("%s*%-%-=%s*"..varname.."%s+"..identifier)
if (var and typ) then
assigns[var] = typ
added = true
else
-- real assignments
local var,typ,rest = tx:match("%s*"..identifier.."%s*=%s*"..identifier.."(.*)")
local comment = rest and rest:match(".*%-%-=%s*"..varname.."%s*$")
local comma = rest and rest:match(".-%s*([,]*)%s*$")
if (var and comment) then
assigns[var] = comment
added = true
elseif (var and typ and comma=="") then
class,func = typ:match(varname.."[%.:]"..varname)
if (func) then
local funcnames = {"new","load","create"}
for i,v in ipairs(funcnames) do
if (func:match("^"..v)) then
assigns[var] = class
added = true
break
end
end
elseif (assigns[typ]) then
assigns[var] = assigns[typ]
added = true
end
end
end
end
line = line+1
end
if (added) then
DisplayOutput("\nTYPES\n")
for i,v in pairs(assigns) do
DisplayOutput(i,v,"\n")
end
end
return assigns
end,
lexerstyleconvert = {
text = {wxstc.wxSTC_LUA_IDENTIFIER,},
lexerdef = {wxstc.wxSTC_LUA_DEFAULT,},
comment = {wxstc.wxSTC_LUA_COMMENT,
wxstc.wxSTC_LUA_COMMENTLINE,
wxstc.wxSTC_LUA_COMMENTDOC,},
stringtxt = {wxstc.wxSTC_LUA_STRING,
wxstc.wxSTC_LUA_CHARACTER,
wxstc.wxSTC_LUA_LITERALSTRING,},
stringeol = {wxstc.wxSTC_LUA_STRINGEOL,},
preprocessor= {wxstc.wxSTC_LUA_PREPROCESSOR,},
operator = {wxstc.wxSTC_LUA_OPERATOR,},
number = {wxstc.wxSTC_LUA_NUMBER,},
keywords0 = {wxstc.wxSTC_LUA_WORD,},
keywords1 = {wxstc.wxSTC_LUA_WORD2,},
keywords2 = {wxstc.wxSTC_LUA_WORD3,},
keywords3 = {wxstc.wxSTC_LUA_WORD4,},
keywords4 = {wxstc.wxSTC_LUA_WORD5,},
keywords5 = {wxstc.wxSTC_LUA_WORD6,},
keywords6 = {wxstc.wxSTC_LUA_WORD7,},
keywords7 = {wxstc.wxSTC_LUA_WORD8,},
},
keywords = {
[[and break do else elseif end false for function if ipairs pairs
in local nil not or repeat return then true until while]],
[[_VERSION assert collectgarbage dofile error gcinfo loadfile loadstring
print rawget rawset require tonumber tostring type unpack]],
[[_G getfenv getmetatable loadlib next pcall
rawequal setfenv setmetatable xpcall
string table math coroutine io os debug
load module select]],
[[string.byte string.char string.dump string.find string.len
string.lower string.rep string.sub string.upper string.format string.gfind string.gsub
table.concat table.foreach table.foreachi table.getn table.sort table.insert table.remove table.setn
math.abs math.acos math.asin math.atan math.atan2 math.ceil math.cos math.deg math.exp
math.floor math.frexp math.ldexp math.log math.log10 math.max math.min math.mod
math.pi math.pow math.rad math.random math.randomseed math.sin math.sqrt math.tan
string.gmatch string.match string.reverse table.maxn
math.cosh math.fmod math.modf math.sinh math.tanh math.huge]],
[[coroutine.create coroutine.resume coroutine.status
coroutine.wrap coroutine.yield
io.close io.flush io.input io.lines io.open io.output io.read io.tmpfile io.type io.write
io.stdin io.stdout io.stderr
os.clock os.date os.difftime os.execute os.exit os.getenv os.remove os.rename
os.setlocale os.time os.tmpname
coroutine.running package.cpath package.loaded package.loadlib package.path
package.preload package.seeall io.popen
debug.debug debug.getfenv debug.gethook debug.getinfo debug.getlocal
debug.getmetatable debug.getregistry debug.getupvalue debug.setfenv
debug.sethook debug.setlocal debug.setmetatable debug.setupvalue debug.traceback]],
},
}
-- authors: Luxinia Dev (Eike Decker & Christoph Kubisch)
---------------------------------------------------------
return {
exts = {"lua"},
lexer = wxstc.wxSTC_LEX_LUA,
apitype = "lua",
linecomment = "--",
sep = "%.:",
isfncall = function(str)
return string.find(str,"([A-Za-z0-9_]+)%s*%(")
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*(%(.-%))")
-- 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*")
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
end
if (s) then
l = string.find(string.sub(str,1,s-1),"local%s+$")
cap = cap .. " " .. (par or "(?)")
end
return s,e,cap,l
end,
typeassigns = function(editor)
local line = editor:GetCurrentLine()
line = line-1
local scopestart = {"if","do","while","function", "local%s+function", "for", "else", "elseif"}
local scopeend = {"end"}
local iscomment = editor.spec.iscomment
local assigns = {}
-- iterate up until a line starts with scopestart
-- always ignore lines whose first symbol is styled as comment
local endline = line
while (line >= 0) do
local ls = editor:PositionFromLine(line)
local s = bit.band(editor:GetStyleAt(ls),31)
if (not iscomment[s]) then
local tx = editor:GetLine(line)
local leftscope
for i,v in ipairs(scopestart) do
if (tx:match("^"..v)) then
leftscope = true
end
end
if (leftscope) then
break
end
end
line = line -1
end
local added
while (line <= endline) do
local ls = editor:PositionFromLine(line)
local s = bit.band(editor:GetStyleAt(ls),31)
if (not iscomment[s]) then
local tx = editor:GetLine(line) --= string
-- check for assignments
local varname = "([%w_%.]+)"
local identifier = "([%w_%.:]+)"
-- special hint
local typ,var = tx:match("%s*%-%-=%s*"..varname.."%s+"..identifier)
if (var and typ) then
assigns[var] = typ
added = true
else
-- real assignments
local var,typ,rest = tx:match("%s*"..identifier.."%s*=%s*"..identifier.."(.*)")
local comment = rest and rest:match(".*%-%-=%s*"..varname.."%s*$")
local comma = rest and rest:match(".-%s*([,]*)%s*$")
if (var and comment) then
assigns[var] = comment
added = true
elseif (var and typ and comma=="") then
class,func = typ:match(varname.."[%.:]"..varname)
if (func) then
local funcnames = {"new","load","create"}
for i,v in ipairs(funcnames) do
if (func:match("^"..v)) then
assigns[var] = class
added = true
break
end
end
elseif (assigns[typ]) then
assigns[var] = assigns[typ]
added = true
end
end
end
end
line = line+1
end
return assigns
end,
lexerstyleconvert = {
text = {wxstc.wxSTC_LUA_IDENTIFIER,},
lexerdef = {wxstc.wxSTC_LUA_DEFAULT,},
comment = {wxstc.wxSTC_LUA_COMMENT,
wxstc.wxSTC_LUA_COMMENTLINE,
wxstc.wxSTC_LUA_COMMENTDOC,},
stringtxt = {wxstc.wxSTC_LUA_STRING,
wxstc.wxSTC_LUA_CHARACTER,
wxstc.wxSTC_LUA_LITERALSTRING,},
stringeol = {wxstc.wxSTC_LUA_STRINGEOL,},
preprocessor= {wxstc.wxSTC_LUA_PREPROCESSOR,},
operator = {wxstc.wxSTC_LUA_OPERATOR,},
number = {wxstc.wxSTC_LUA_NUMBER,},
keywords0 = {wxstc.wxSTC_LUA_WORD,},
keywords1 = {wxstc.wxSTC_LUA_WORD2,},
keywords2 = {wxstc.wxSTC_LUA_WORD3,},
keywords3 = {wxstc.wxSTC_LUA_WORD4,},
keywords4 = {wxstc.wxSTC_LUA_WORD5,},
keywords5 = {wxstc.wxSTC_LUA_WORD6,},
keywords6 = {wxstc.wxSTC_LUA_WORD7,},
keywords7 = {wxstc.wxSTC_LUA_WORD8,},
},
keywords = {
[[and break do else elseif end false for function if ipairs pairs
in local nil not or repeat return then true until while]],
[[_VERSION assert collectgarbage dofile error gcinfo loadfile loadstring
print rawget rawset require tonumber tostring type unpack]],
[[_G getfenv getmetatable loadlib next pcall
rawequal setfenv setmetatable xpcall
string table math coroutine io os debug
load module select]],
[[string.byte string.char string.dump string.find string.len
string.lower string.rep string.sub string.upper string.format string.gfind string.gsub
table.concat table.foreach table.foreachi table.getn table.sort table.insert table.remove table.setn
math.abs math.acos math.asin math.atan math.atan2 math.ceil math.cos math.deg math.exp
math.floor math.frexp math.ldexp math.log math.log10 math.max math.min math.mod
math.pi math.pow math.rad math.random math.randomseed math.sin math.sqrt math.tan
string.gmatch string.match string.reverse table.maxn
math.cosh math.fmod math.modf math.sinh math.tanh math.huge]],
[[coroutine.create coroutine.resume coroutine.status
coroutine.wrap coroutine.yield
io.close io.flush io.input io.lines io.open io.output io.read io.tmpfile io.type io.write
io.stdin io.stdout io.stderr
os.clock os.date os.difftime os.execute os.exit os.getenv os.remove os.rename
os.setlocale os.time os.tmpname
coroutine.running package.cpath package.loaded package.loadlib package.path
package.preload package.seeall io.popen
debug.debug debug.getfenv debug.gethook debug.getinfo debug.getlocal
debug.getmetatable debug.getregistry debug.getupvalue debug.setfenv
debug.sethook debug.setlocal debug.setmetatable debug.setupvalue debug.traceback]],
},
}

View File

@@ -2,68 +2,67 @@
---------------------------------------------------------
return {
exts = {"prt","shd","mtl"},
lexer = wxstc.wxSTC_LEX_POV,
apitype = "luxres",
linecomment = "//",
lexerstyleconvert = {
text = {wxstc.wxSTC_POV_IDENTIFIER,},
lexerdef = {wxstc.wxSTC_POV_DEFAULT,},
comment = {wxstc.wxSTC_POV_COMMENT,
wxstc.wxSTC_POV_COMMENTLINE,},
stringtxt = {wxstc.wxSTC_POV_STRING,},
stringeol = {wxstc.wxSTC_POV_STRINGEOL,},
--preprocessor= {wxstc.wxSTC_POV_PREPROCESSOR,},
operator = {wxstc.wxSTC_POV_OPERATOR,},
number = {wxstc.wxSTC_POV_NUMBER,},
keywords0 = {wxstc.wxSTC_POV_WORD2,},
keywords1 = {wxstc.wxSTC_POV_WORD3,},
keywords2 = {wxstc.wxSTC_POV_WORD4,},
keywords3 = {wxstc.wxSTC_POV_WORD5,},
keywords4 = {wxstc.wxSTC_POV_WORD6,},
keywords5 = {wxstc.wxSTC_POV_WORD7,},
keywords6 = {wxstc.wxSTC_POV_WORD8,},
},
exts = {"prt","shd","mtl"},
lexer = wxstc.wxSTC_LEX_POV,
apitype = "luxres",
linecomment = "//",
lexerstyleconvert = {
text = {wxstc.wxSTC_POV_IDENTIFIER,},
keywords = {
-- word0 doesnt exist in lexer
"",
[[RenderFlag Color Texture Forces SubSystem Emitter Particle Technique GpuProgram Shader
NewPass DrawPass ]],
lexerdef = {wxstc.wxSTC_POV_DEFAULT,},
comment = {wxstc.wxSTC_POV_COMMENT,
wxstc.wxSTC_POV_COMMENTLINE,},
stringtxt = {wxstc.wxSTC_POV_STRING,},
stringeol = {wxstc.wxSTC_POV_STRINGEOL,},
--preprocessor= {wxstc.wxSTC_POV_PREPROCESSOR,},
operator = {wxstc.wxSTC_POV_OPERATOR,},
number = {wxstc.wxSTC_POV_NUMBER,},
[[control floatmod texcontrol shdcontrol texconst texcenter texscale texrotate texmove texgenplane texclamp
frames delay loop param alpha rfalpha layer alphaTEX alphafunc texmatrixcolum
blendmode texcoord count type size width height axis model rate
alphaTEX alphamode stateflag velocity endtime maxoffsetdist velocityvar flipdirection spread restarttime
restarts life size sizeage3 sizevar lifevar rotate rotatevar rotateoffset rotateage3
RGBAvar pointparams speedage3 numcolor numtex originoffset gravity wind trail normal
translated instancemesh rotateagetex speedagetex sizeagetex RGBAagetex RGBAvar TEXPROJ TEXCUBE TEXALPHA
TEX TEXDOTZ VTEXPROJ VTEXCUBE VTEXALPHA VTEX VTEXDOTZ SHD RGBA BASE
SKIN FOGGED TEXCOMBINE1D MATERIAL TEXCOMBINE2D_16 TEXCOMBINE2D_32 ]],
keywords0 = {wxstc.wxSTC_POV_WORD2,},
keywords1 = {wxstc.wxSTC_POV_WORD3,},
keywords2 = {wxstc.wxSTC_POV_WORD4,},
keywords3 = {wxstc.wxSTC_POV_WORD5,},
keywords4 = {wxstc.wxSTC_POV_WORD6,},
keywords5 = {wxstc.wxSTC_POV_WORD7,},
keywords6 = {wxstc.wxSTC_POV_WORD8,},
},
[[VID_REPLACE VID_DECAL VID_DECAL_PREV VID_DECAL_VERTEX VID_DECAL_CONST VID_MODULATE VID_ADD VID_AMODADD VID_AMODADD_PREV VID_AMODADD_VERTEX
VID_AMODADD_CONST VID_AMODADD_CONSTMOD VID_NORMALMAPTAN VID_DECAL_CONSTMOD VID_LIGHTPOS VID_LIGHTCOLOR VID_LIGHTDIR VID_CAMPOS VID_CAMDIR VID_ARRAY
VID_LIGHTAMBIENT VID_VALUE VID_LIGHTRANGE VID_RANDOM VID_TIME VID_TEXCONST VID_TEXSIZE VID_TEXSIZEINV VID_TEXLMSCALE VID_TEXMAT0
VID_TEXMAT1 VID_TEXMAT2 VID_TEXMAT3 VID_TEXGEN0 VID_TEXGEN1 VID_TEXGEN2 VID_TEXGEN3 RENDER_BLEND RENDER_NOVERTEXCOLOR RENDER_ALPHATEST
RENDER_STENCILTEST RENDER_NODEPTHTEST RENDER_NOCULL RENDER_FRONTCULL RENDER_NOCOLORMASK RENDER_NODEPTHMASK RENDER_STENCILMASK RENDER_LIT ADD SIN
COS ZIGZAG USER_TEX LIGHTMAP ATTENUATE3D NORMALIZE SKYBOX SPECULAR DIFFUSE DUMMY
VID_DEFAULT VID_LOWDETAIL VID_ARB_V VID_ARB_V_TEX4 VID_ARB_V_TEX8 VID_ARB_TEXCOMB VID_ARB_TEXCOMB_TEX4 VID_ARB_VF VID_ARB_VF_TEX4 VID_ARB_VF_TEX8
VID_CG_SM3_TEX8 VID_CG_SM3 VID_CG_SM4 VID_CG_SM4_GS GL_NEVER GL_ALWAYS GL_LESS GL_GREATER GL_LEQUAL GL_GEQUAL
GL_EQUAL GL_NOTEQUAL VID_POINT VID_CIRCLE VID_SPHERE VID_RECTANGLE VID_MODEL VID_QUAD VID_TRIANGLE VID_HSPHERE
VID_DIR VID_ODIR CAP_MODADD CAP_COMBINE4 CAP_TEX3D CAP_TEXFLOAT ]],
keywords = {
-- word0 doesnt exist in lexer
"",
[[RenderFlag Color Texture Forces SubSystem Emitter Particle Technique GpuProgram Shader
NewPass DrawPass ]],
[[reflectmap blendinvertalpha spheremap screenmap interpolate skyreflectmap nocolorarray lit unlit sunlit
nocull nodepthmask alphamask eyelinmap normalmap sunreflectmap sunnormalmap vertexcolored tangents normals
colorpass nodepthtest sort novistest depthmask nodraw depthcompare depthvalue nomipmap fog
rotatevelocity dieonfrontplane camrotfix noagedeath pointsmooth noage eventimed sequence combinedraw skymatrix
lightmapscale rgbscale2 rgbscale4 alphascale2 alphascale4 lightreflectmap0 lightreflectmap1 lightreflectmap2 lightreflectmap3 lightnormalmap0
lightnormalmap1 lightnormalmap2 lightnormalmap3 lowCgProfile VPROG VCG FCG GCG FPROG FFIXED
VFIXED GFIXED ]],
[[control floatmod texcontrol shdcontrol texconst texcenter texscale texrotate texmove texgenplane texclamp
frames delay loop param alpha rfalpha layer alphaTEX alphafunc texmatrixcolum
blendmode texcoord count type size width height axis model rate
alphaTEX alphamode stateflag velocity endtime maxoffsetdist velocityvar flipdirection spread restarttime
restarts life size sizeage3 sizevar lifevar rotate rotatevar rotateoffset rotateage3
RGBAvar pointparams speedage3 numcolor numtex originoffset gravity wind trail normal
translated instancemesh rotateagetex speedagetex sizeagetex RGBAagetex RGBAvar TEXPROJ TEXCUBE TEXALPHA
TEX TEXDOTZ VTEXPROJ VTEXCUBE VTEXALPHA VTEX VTEXDOTZ SHD RGBA BASE
SKIN FOGGED TEXCOMBINE1D MATERIAL TEXCOMBINE2D_16 TEXCOMBINE2D_32 ]],
[[luxinia_ParticleSys_v120 luxinia_Shader_v310 luxinia_Material_v110 IF ELSEIF ELSE ]],
[[VID_REPLACE VID_DECAL VID_DECAL_PREV VID_DECAL_VERTEX VID_DECAL_CONST VID_MODULATE VID_ADD VID_AMODADD VID_AMODADD_PREV VID_AMODADD_VERTEX
VID_AMODADD_CONST VID_AMODADD_CONSTMOD VID_NORMALMAPTAN VID_DECAL_CONSTMOD VID_LIGHTPOS VID_LIGHTCOLOR VID_LIGHTDIR VID_CAMPOS VID_CAMDIR VID_ARRAY
VID_LIGHTAMBIENT VID_VALUE VID_LIGHTRANGE VID_RANDOM VID_TIME VID_TEXCONST VID_TEXSIZE VID_TEXSIZEINV VID_TEXLMSCALE VID_TEXMAT0
VID_TEXMAT1 VID_TEXMAT2 VID_TEXMAT3 VID_TEXGEN0 VID_TEXGEN1 VID_TEXGEN2 VID_TEXGEN3 RENDER_BLEND RENDER_NOVERTEXCOLOR RENDER_ALPHATEST
RENDER_STENCILTEST RENDER_NODEPTHTEST RENDER_NOCULL RENDER_FRONTCULL RENDER_NOCOLORMASK RENDER_NODEPTHMASK RENDER_STENCILMASK RENDER_LIT ADD SIN
COS ZIGZAG USER_TEX LIGHTMAP ATTENUATE3D NORMALIZE SKYBOX SPECULAR DIFFUSE DUMMY
VID_DEFAULT VID_LOWDETAIL VID_ARB_V VID_ARB_V_TEX4 VID_ARB_V_TEX8 VID_ARB_TEXCOMB VID_ARB_TEXCOMB_TEX4 VID_ARB_VF VID_ARB_VF_TEX4 VID_ARB_VF_TEX8
VID_CG_SM3_TEX8 VID_CG_SM3 VID_CG_SM4 VID_CG_SM4_GS GL_NEVER GL_ALWAYS GL_LESS GL_GREATER GL_LEQUAL GL_GEQUAL
GL_EQUAL GL_NOTEQUAL VID_POINT VID_CIRCLE VID_SPHERE VID_RECTANGLE VID_MODEL VID_QUAD VID_TRIANGLE VID_HSPHERE
VID_DIR VID_ODIR CAP_MODADD CAP_COMBINE4 CAP_TEX3D CAP_TEXFLOAT ]],
},
}
[[reflectmap blendinvertalpha spheremap screenmap interpolate skyreflectmap nocolorarray lit unlit sunlit
nocull nodepthmask alphamask eyelinmap normalmap sunreflectmap sunnormalmap vertexcolored tangents normals
colorpass nodepthtest sort novistest depthmask nodraw depthcompare depthvalue nomipmap fog
rotatevelocity dieonfrontplane camrotfix noagedeath pointsmooth noage eventimed sequence combinedraw skymatrix
lightmapscale rgbscale2 rgbscale4 alphascale2 alphascale4 lightreflectmap0 lightreflectmap1 lightreflectmap2 lightreflectmap3 lightnormalmap0
lightnormalmap1 lightnormalmap2 lightnormalmap3 lowCgProfile VPROG VCG FCG GCG FPROG FFIXED
VFIXED GFIXED ]],
[[luxinia_ParticleSys_v120 luxinia_Shader_v310 luxinia_Material_v110 IF ELSEIF ELSE ]],
},
}

View File

@@ -1,115 +1,114 @@
-- authors: Luxinia Dev (Eike Decker & Christoph Kubisch)
---------------------------------------------------------
return {
-- unfortunately no good lexer
-- ASM comments start with ;
-- and TCL doesnt allow coloring
-- behind keywords
exts = {"glp","vp","fp"},
lexer = wxstc.wxSTC_LEX_TCL,
--apitype = "cg",
linecomment = "#",
lexerstyleconvert = {
text = {4,5,7,8,9,10,11,
},
lexerdef = {0,},
comment = {1,2,20,21,
},
--stringtxt = {wxstc.wxSTC_SQL_STRING,
-- wxstc.wxSTC_SQL_CHARACTER,
-- },
--stringeol = {wxstc.wxSTC_SQL_STRINGEOL,},
--preprocessor= {,},
operator = {6,},
number = {3,
},
keywords0 = {12,},
keywords1 = {13,},
keywords2 = {14,},
keywords3 = {15,},
},
keywords = {
[[EMIT ENDPRIM
ABS ADD AND BRK CAL CEIL CMP CONT COS DIV DP2 DP2A DP3 DP4 DPH DST ELSE
ENDIF ENDREP EX2 FLR FRC I2F IF KIL LG2 LIT LRP MAD MAX MIN MOD MOV MUL
NOT NRM OR PK2H PK2US PK4B PK4UB POW RCC RCP REP RET RFL ROUND RSQ SAD
SCS SEQ SFL SGE SGT SHL SHR SIN SLE SLT SNE SSG STR SUB SWZ TEX TRUNC LOOP
TXB TXD TXF TXL TXP TXQ UP2H UP2US UP4B UP4UB X2D XOR XPD REP.S REP.F REP.U
ENDLOOP SUBROUTINENUM CALI
ABS_SAT ADD_SAT CEIL_SAT CMP_SAT COS_SAT DIV_SAT DP2_SAT DP2A_SAT DP3_SAT
DP4_SAT DPH_SAT DST_SAT EX2_SAT FLR_SAT FRC_SAT LG2_SAT LIT_SAT LRP_SAT
MAD_SAT MAX_SAT MIN_SAT MOV_SAT MUL_SAT NRM_SAT POW_SAT RCC_SAT RCP_SAT
RFL_SAT ROUND_SAT RSQ_SAT SCS_SAT SEQ_SAT SFL_SAT SGE_SAT SGT_SAT SIN_SAT
SLE_SAT SLT_SAT SNE_SAT SSG_SAT STR_SAT SUB_SAT SWZ_SAT TEX_SAT TRUNC_SAT
TXB_SAT TXD_SAT TXF_SAT TXL_SAT TXP_SAT UP2H_SAT UP2US_SAT UP4B_SAT UP4UB_SAT
X2D_SAT XPD_SAT
]],
[[
ATTRIB PARAM TEMP ADDRESS OUTPUT ALIAS OPTION TEXTURE
PRIMITIVE_IN PRIMITIVE_OUT VERTICES_OUT POINTS LINES LINES_ADJACENCY
TRIANGLES TRIANGLES_ADJACENCY
LINE_STRIP TRIANGLE_STRIP
EQ GE GT LE LT NE TR FL EQ0 GE0 GT0 LE0 LT0 NE0 TR0 FL0 EQ1 GE1 GT1 LE1 LT1
NE1 TR1 FL1 NAN NAN0 NAN1 LEG LEG0 LEG1 CF CF0 CF1 NCF NCF0 NCF1 OF OF0 OF1
NOF NOF0 NOF1 AB AB0 AB1 BLE BLE0 BLE1 SF SF0 SF1 NSF NSF0 NSF1
END SUBROUTINETYPE SUBROUTINE
]],
[[
vertex position weight normal color primary secondary fogcoord texcoord
matrixindex attrib
program env local fragment
state material ambient diffuse specular emission shininess front back
light attenuation spot direction half
lightmodel scene lightprod
texgen eye object s t r q
fog params
clip plane
point size attenuation
matrix modelview projection mvp texture palette row transpose inverse invtrans
result pointsize 1D 2D 3D CUBE RECT
]],
[[
x y z w xxxx xxxy xxxz xxxw
xxyx xxyy xxyz xxyw xxzx xxzy xxzz xxzw xxwx xxwy
xxwz xxww xyxx xyxy xyxz xyxw xyyx xyyy xyyz xyyw
xyzx xyzy xyzz xyzw xywx xywy xywz xyww xzxx xzxy
xzxz xzxw xzyx xzyy xzyz xzyw xzzx xzzy xzzz xzzw
xzwx xzwy xzwz xzww xwxx xwxy xwxz xwxw xwyx xwyy
xwyz xwyw xwzx xwzy xwzz xwzw xwwx xwwy xwwz xwww
yxxx yxxy yxxz yxxw yxyx yxyy yxyz yxyw yxzx yxzy
yxzz yxzw yxwx yxwy yxwz yxww yyxx yyxy yyxz yyxw
yyyx yyyy yyyz yyyw yyzx yyzy yyzz yyzw yywx yywy
yywz yyww yzxx yzxy yzxz yzxw yzyx yzyy yzyz yzyw
yzzx yzzy yzzz yzzw yzwx yzwy yzwz yzww ywxx ywxy
ywxz ywxw ywyx ywyy ywyz ywyw ywzx ywzy ywzz ywzw
ywwx ywwy ywwz ywww zxxx zxxy zxxz zxxw zxyx zxyy
zxyz zxyw zxzx zxzy zxzz zxzw zxwx zxwy zxwz zxww
zyxx zyxy zyxz zyxw zyyx zyyy zyyz zyyw zyzx zyzy
zyzz zyzw zywx zywy zywz zyww zzxx zzxy zzxz zzxw
zzyx zzyy zzyz zzyw zzzx zzzy zzzz zzzw zzwx zzwy
zzwz zzww zwxx zwxy zwxz zwxw zwyx zwyy zwyz zwyw
zwzx zwzy zwzz zwzw zwwx zwwy zwwz zwww wxxx wxxy
wxxz wxxw wxyx wxyy wxyz wxyw wxzx wxzy wxzz wxzw
wxwx wxwy wxwz wxww wyxx wyxy wyxz wyxw wyyx wyyy
wyyz wyyw wyzx wyzy wyzz wyzw wywx wywy wywz wyww
wzxx wzxy wzxz wzxw wzyx wzyy wzyz wzyw wzzx wzzy
wzzz wzzw wzwx wzwy wzwz wzww wwxx wwxy wwxz wwxw
wwyx wwyy wwyz wwyw wwzx wwzy wwzz wwzw wwwx wwwy
wwwz wwww xy xz yz xyz xw yw xyw zw
xzw yzw xyzw ]],
},
}
-- authors: Luxinia Dev (Eike Decker & Christoph Kubisch)
---------------------------------------------------------
return {
-- unfortunately no good lexer
-- ASM comments start with ;
-- and TCL doesnt allow coloring
-- behind keywords
exts = {"glp","vp","fp"},
lexer = wxstc.wxSTC_LEX_TCL,
--apitype = "cg",
linecomment = "#",
lexerstyleconvert = {
text = {4,5,7,8,9,10,11,
},
lexerdef = {0,},
comment = {1,2,20,21,
},
--stringtxt = {wxstc.wxSTC_SQL_STRING,
-- wxstc.wxSTC_SQL_CHARACTER,
-- },
--stringeol = {wxstc.wxSTC_SQL_STRINGEOL,},
--preprocessor= {,},
operator = {6,},
number = {3,
},
keywords0 = {12,},
keywords1 = {13,},
keywords2 = {14,},
keywords3 = {15,},
},
keywords = {
[[EMIT ENDPRIM
ABS ADD AND BRK CAL CEIL CMP CONT COS DIV DP2 DP2A DP3 DP4 DPH DST ELSE
ENDIF ENDREP EX2 FLR FRC I2F IF KIL LG2 LIT LRP MAD MAX MIN MOD MOV MUL
NOT NRM OR PK2H PK2US PK4B PK4UB POW RCC RCP REP RET RFL ROUND RSQ SAD
SCS SEQ SFL SGE SGT SHL SHR SIN SLE SLT SNE SSG STR SUB SWZ TEX TRUNC LOOP
TXB TXD TXF TXL TXP TXQ UP2H UP2US UP4B UP4UB X2D XOR XPD REP.S REP.F REP.U
ENDLOOP SUBROUTINENUM CALI
ABS_SAT ADD_SAT CEIL_SAT CMP_SAT COS_SAT DIV_SAT DP2_SAT DP2A_SAT DP3_SAT
DP4_SAT DPH_SAT DST_SAT EX2_SAT FLR_SAT FRC_SAT LG2_SAT LIT_SAT LRP_SAT
MAD_SAT MAX_SAT MIN_SAT MOV_SAT MUL_SAT NRM_SAT POW_SAT RCC_SAT RCP_SAT
RFL_SAT ROUND_SAT RSQ_SAT SCS_SAT SEQ_SAT SFL_SAT SGE_SAT SGT_SAT SIN_SAT
SLE_SAT SLT_SAT SNE_SAT SSG_SAT STR_SAT SUB_SAT SWZ_SAT TEX_SAT TRUNC_SAT
TXB_SAT TXD_SAT TXF_SAT TXL_SAT TXP_SAT UP2H_SAT UP2US_SAT UP4B_SAT UP4UB_SAT
X2D_SAT XPD_SAT
]],
[[
ATTRIB PARAM TEMP ADDRESS OUTPUT ALIAS OPTION TEXTURE
PRIMITIVE_IN PRIMITIVE_OUT VERTICES_OUT POINTS LINES LINES_ADJACENCY
TRIANGLES TRIANGLES_ADJACENCY
LINE_STRIP TRIANGLE_STRIP
EQ GE GT LE LT NE TR FL EQ0 GE0 GT0 LE0 LT0 NE0 TR0 FL0 EQ1 GE1 GT1 LE1 LT1
NE1 TR1 FL1 NAN NAN0 NAN1 LEG LEG0 LEG1 CF CF0 CF1 NCF NCF0 NCF1 OF OF0 OF1
NOF NOF0 NOF1 AB AB0 AB1 BLE BLE0 BLE1 SF SF0 SF1 NSF NSF0 NSF1
END SUBROUTINETYPE SUBROUTINE
]],
[[
vertex position weight normal color primary secondary fogcoord texcoord
matrixindex attrib
program env local fragment
state material ambient diffuse specular emission shininess front back
light attenuation spot direction half
lightmodel scene lightprod
texgen eye object s t r q
fog params
clip plane
point size attenuation
matrix modelview projection mvp texture palette row transpose inverse invtrans
result pointsize 1D 2D 3D CUBE RECT
]],
[[
x y z w xxxx xxxy xxxz xxxw
xxyx xxyy xxyz xxyw xxzx xxzy xxzz xxzw xxwx xxwy
xxwz xxww xyxx xyxy xyxz xyxw xyyx xyyy xyyz xyyw
xyzx xyzy xyzz xyzw xywx xywy xywz xyww xzxx xzxy
xzxz xzxw xzyx xzyy xzyz xzyw xzzx xzzy xzzz xzzw
xzwx xzwy xzwz xzww xwxx xwxy xwxz xwxw xwyx xwyy
xwyz xwyw xwzx xwzy xwzz xwzw xwwx xwwy xwwz xwww
yxxx yxxy yxxz yxxw yxyx yxyy yxyz yxyw yxzx yxzy
yxzz yxzw yxwx yxwy yxwz yxww yyxx yyxy yyxz yyxw
yyyx yyyy yyyz yyyw yyzx yyzy yyzz yyzw yywx yywy
yywz yyww yzxx yzxy yzxz yzxw yzyx yzyy yzyz yzyw
yzzx yzzy yzzz yzzw yzwx yzwy yzwz yzww ywxx ywxy
ywxz ywxw ywyx ywyy ywyz ywyw ywzx ywzy ywzz ywzw
ywwx ywwy ywwz ywww zxxx zxxy zxxz zxxw zxyx zxyy
zxyz zxyw zxzx zxzy zxzz zxzw zxwx zxwy zxwz zxww
zyxx zyxy zyxz zyxw zyyx zyyy zyyz zyyw zyzx zyzy
zyzz zyzw zywx zywy zywz zyww zzxx zzxy zzxz zzxw
zzyx zzyy zzyz zzyw zzzx zzzy zzzz zzzw zzwx zzwy
zzwz zzww zwxx zwxy zwxz zwxw zwyx zwyy zwyz zwyw
zwzx zwzy zwzz zwzw zwwx zwwy zwwz zwww wxxx wxxy
wxxz wxxw wxyx wxyy wxyz wxyw wxzx wxzy wxzz wxzw
wxwx wxwy wxwz wxww wyxx wyxy wyxz wyxw wyyx wyyy
wyyz wyyw wyzx wyzy wyzz wyzw wywx wywy wywz wyww
wzxx wzxy wzxz wzxw wzyx wzyy wzyz wzyw wzzx wzzy
wzzz wzzw wzwx wzwy wzwz wzww wwxx wwxy wwxz wwxw
wwyx wwyy wwyz wwyw wwzx wwzy wwzz wwzw wwwx wwwy
wwwz wwww xy xz yz xyz xw yw xyw zw
xzw yzw xyzw ]],
},
}

View File

@@ -4,195 +4,192 @@
local convtypes = [[bool char uchar short ushort int uint long ulong float double]]
local convout = {}
for i in convtypes:gmatch("([%w_]+)") do
local suffix = {"","_rte","_rtz","_rtp","_rtn"}
for k,t in ipairs(suffix) do
table.insert(convout,"convert_"..i..t)
table.insert(convout,"convert_"..i.."_sat"..t)
local vectors = {2,4,8,16}
for n,v in ipairs(vectors) do
table.insert(convout,"convert_"..i..v..t)
table.insert(convout,"convert_"..i..v.."_sat"..t)
end
end
local suffix = {"","_rte","_rtz","_rtp","_rtn"}
for k,t in ipairs(suffix) do
table.insert(convout,"convert_"..i..t)
table.insert(convout,"convert_"..i.."_sat"..t)
local vectors = {2,4,8,16}
for n,v in ipairs(vectors) do
table.insert(convout,"convert_"..i..v..t)
table.insert(convout,"convert_"..i..v.."_sat"..t)
end
end
end
convout = table.concat(convout, " ")
local astypes = [[int uint uchar ushort float double size_t ptrdiff_t intptr_t uintptr_t
long ulong char short unsigned
float2 float4 float8 float16
double2 double4 double8 double16
char2 char4 char8 char16
uchar2 uchar4 uchar8 uchar16
short2 short4 short8 short16
ushort2 ushort4 ushort8 ushort16
int2 int4 int8 int16
uint2 uint4 uint8 uint16
long2 long4 long8 long16
ulong2 ulong4 ulong8 ulong16]]
long ulong char short unsigned
float2 float4 float8 float16
double2 double4 double8 double16
char2 char4 char8 char16
uchar2 uchar4 uchar8 uchar16
short2 short4 short8 short16
ushort2 ushort4 ushort8 ushort16
int2 int4 int8 int16
uint2 uint4 uint8 uint16
long2 long4 long8 long16
ulong2 ulong4 ulong8 ulong16]]
local astypeout = {}
for i in astypes:gmatch("([%w_]+)") do
table.insert(astypeout, "as_"..i)
table.insert(astypeout, "as_"..i)
end
astypeout = table.concat(astypeout, " ")
return {
exts = {"cl","ocl","clh",},
lexer = wxstc.wxSTC_LEX_CPP,
apitype = "opencl",
sep = "%.",
linecomment = "//",
isfndef = function(str)
local l
local s,e,cap = string.find(str,"^%s*([A-Za-z0-9_]+%s+[A-Za-z0-9_]+%s*%(.+%))")
if (not s) then
s,e,cap = string.find(str,"^%s*([A-Za-z0-9_]+%s+[A-Za-z0-9_]+)%s*%(")
end
if (cap and (string.find(cap,"^return") or string.find(cap,"else"))) then return end
return s,e,cap,l
end,
lexerstyleconvert = {
text = {wxstc.wxSTC_C_IDENTIFIER,
wxstc.wxSTC_C_VERBATIM,
wxstc.wxSTC_C_REGEX,
wxstc.wxSTC_C_REGEX,
wxstc.wxSTC_C_GLOBALCLASS,},
lexerdef = {wxstc.wxSTC_C_DEFAULT,},
comment = {wxstc.wxSTC_C_COMMENT,
wxstc.wxSTC_C_COMMENTLINE,
wxstc.wxSTC_C_COMMENTDOC,
wxstc.wxSTC_C_COMMENTLINEDOC,
wxstc.wxSTC_C_COMMENTDOCKEYWORD,
wxstc.wxSTC_C_COMMENTDOCKEYWORDERROR,},
stringtxt = {wxstc.wxSTC_C_STRING,
wxstc.wxSTC_C_CHARACTER,
wxstc.wxSTC_C_UUID,},
stringeol = {wxstc.wxSTC_C_STRINGEOL,},
preprocessor= {wxstc.wxSTC_C_PREPROCESSOR,},
operator = {wxstc.wxSTC_C_OPERATOR,},
number = {wxstc.wxSTC_C_NUMBER,
wxstc.wxSTC_C_WORD},
keywords0 = {wxstc.wxSTC_C_WORD,},
keywords1 = {wxstc.wxSTC_C_WORD2,},
},
keywords = {
[[int uint uchar ushort float double size_t ptrdiff_t intptr_t uintptr_t
long ulong char short unsigned
float2 float4 float8 float16
double2 double4 double8 double16
char2 char4 char8 char16
uchar2 uchar4 uchar8 uchar16
short2 short4 short8 short16
ushort2 ushort4 ushort8 ushort16
int2 int4 int8 int16
uint2 uint4 uint8 uint16
long2 long4 long8 long16
ulong2 ulong4 ulong8 ulong16
half2 half4 half8 half16
void half bool
image2d_t image3d_t sampler_t event_t cl_image_format
struct typedef void const inline
return switch case for do while if else break continue volatile
CLK_A CLK_R CLK_RG CLK_RGB CLK_RGBA CLK_ARGB CLK_BGRA CLK_INTENSITY CLK_LUMINANCE
MAXFLOAT HUGE_VALF INFINITY NAN
CLK_LOCAL_MEM_FENCE CLK_GLOBAL_MEM_FENCE
CLK_SNORM_INT8
CLK_SNORM_INT16
CLK_UNORM_INT8
CLK_UNORM_INT16
CLK_UNORM_SHORT_565
CLK_UNORM_SHORT_555
CLK_UNORM_SHORT_101010
CLK_SIGNED_INT8
CLK_SIGNED_INT16
CLK_SIGNED_INT32
CLK_UNSIGNED_INT8
CLK_UNSIGNED_INT16
CLK_UNSIGNED_INT32
CLK_HALF_FLOAT
CLK_FLOAT
__FILE__ __LINE__ __OPENCL_VERSION__ __ENDIAN_LITTLE__
__ROUNDING_MODE__ __IMAGE_SUPPORT__ __FAST_RELAXED_MATH__
]],
exts = {"cl","ocl","clh",},
lexer = wxstc.wxSTC_LEX_CPP,
apitype = "opencl",
sep = "%.",
linecomment = "//",
[[__kernel kernel __attribute__ __read_only __write_only read_only write_only
__constant constant __local local __global global __private private
vec_type_hint work_group_size_hint reqd_work_group_size
aligned packed endian host device
async_work_group_copy wait_group_events prefetch
clamp min max degrees radians sign smoothstep step mix
mem_fence read_mem_fence write_mem_fence
cross prod distance dot length normalize fast_distance fast_length fast_normalize
get_image_width get_image_height get_image_depth
get_image_channel_data_type get_image_channel_order
get_image_dim
abs abs_diff add_sat clz hadd mad24 mad_hi mad_sat
mul24 mul_hi rhadd rotate sub_sat upsample
read_imagei write_imagei read_imageui write_imageui
read_imagef write_imagef
isequal isnotequal isgreater isgreaterequal isless islessequal islessgreater
isfinite isinf isnan isnormal isordered isunordered signbit any all bitselect select
acos acosh acospi asin asinh asinpi atan atan2 atanh atanpi atan2pi
cbrt ceil copysign cos half_cos native_cos cosh cospi half_divide native_divide
erf erfc exp half_exp native_exp exp2 half_exp2 native_exp2 exp10 half_exp10 native_exp10
expm1 fabs fdim floor fma fmax fmin fmod fract frexp hypot ilogb
ldexp lgamma lgamma_r log half_log native_log log2 half_log2 native_log2
log10 half_log10 native_log10 log1p logb mad modf nan nextafter
pow pown powr half_powr native_powr half_recip native_recip
remainder remquo rint round rootn rsqrt half_rsqrt native_rsqrt
sin half_sin native_sin sincos sinh sinpi sqrt half_sqrt native_sqrt
tan half_tan native_tan tanh tanpi tgamma trunc
barrier
vload2 vload4 vload8 vload16
vload_half vload_half2 vload_half4 vload_half8 vload_half16 vloada_half4 vloada_half8 vloada_half16
vstore2 vstore4 vstore8 vstore16
vstore_half vstore_half2 vstore_half4 vstore_half8 vstore_half16 vstorea_half4 vstorea_half8 vstorea_half16
get_global_id get_global_size get_group_id get_local_id get_local_size get_num_groups get_work_dim
x y z w
xxxx xxxy xxxz xxxw xxyx xxyy xxyz xxyw xxzx xxzy
xxzz xxzw xxwx xxwy xxwz xxww xyxx xyxy xyxz xyxw
xyyx xyyy xyyz xyyw xyzx xyzy xyzz xyzw xywx xywy
xywz xyww xzxx xzxy xzxz xzxw xzyx xzyy xzyz xzyw
xzzx xzzy xzzz xzzw xzwx xzwy xzwz xzww xwxx xwxy
xwxz xwxw xwyx xwyy xwyz xwyw xwzx xwzy xwzz xwzw
xwwx xwwy xwwz xwww yxxx yxxy yxxz yxxw yxyx yxyy
yxyz yxyw yxzx yxzy yxzz yxzw yxwx yxwy yxwz yxww
yyxx yyxy yyxz yyxw yyyx yyyy yyyz yyyw yyzx yyzy
yyzz yyzw yywx yywy yywz yyww yzxx yzxy yzxz yzxw
yzyx yzyy yzyz yzyw yzzx yzzy yzzz yzzw yzwx yzwy
yzwz yzww ywxx ywxy ywxz ywxw ywyx ywyy ywyz ywyw
ywzx ywzy ywzz ywzw ywwx ywwy ywwz ywww zxxx zxxy
zxxz zxxw zxyx zxyy zxyz zxyw zxzx zxzy zxzz zxzw
zxwx zxwy zxwz zxww zyxx zyxy zyxz zyxw zyyx zyyy
zyyz zyyw zyzx zyzy zyzz zyzw zywx zywy zywz zyww
zzxx zzxy zzxz zzxw zzyx zzyy zzyz zzyw zzzx zzzy
zzzz zzzw zzwx zzwy zzwz zzww zwxx zwxy zwxz zwxw
zwyx zwyy zwyz zwyw zwzx zwzy zwzz zwzw zwwx zwwy
zwwz zwww wxxx wxxy wxxz wxxw wxyx wxyy wxyz wxyw
wxzx wxzy wxzz wxzw wxwx wxwy wxwz wxww wyxx wyxy
wyxz wyxw wyyx wyyy wyyz wyyw wyzx wyzy wyzz wyzw
wywx wywy wywz wyww wzxx wzxy wzxz wzxw wzyx wzyy
wzyz wzyw wzzx wzzy wzzz wzzw wzwx wzwy wzwz wzww
wwxx wwxy wwxz wwxw wwyx wwyy wwyz wwyw wwzx wwzy
wwzz wwzw wwwx wwwy wwwz wwww xy xz yz xyz
xw yw xyw zw xzw yzw xyzw ]]..convout.." "..astypeout,
isfndef = function(str)
local l
local s,e,cap = string.find(str,"^%s*([A-Za-z0-9_]+%s+[A-Za-z0-9_]+%s*%(.+%))")
if (not s) then
s,e,cap = string.find(str,"^%s*([A-Za-z0-9_]+%s+[A-Za-z0-9_]+)%s*%(")
end
if (cap and (string.find(cap,"^return") or string.find(cap,"else"))) then return end
return s,e,cap,l
end,
},
}
lexerstyleconvert = {
text = {wxstc.wxSTC_C_IDENTIFIER,
wxstc.wxSTC_C_VERBATIM,
wxstc.wxSTC_C_REGEX,
wxstc.wxSTC_C_REGEX,
wxstc.wxSTC_C_GLOBALCLASS,},
lexerdef = {wxstc.wxSTC_C_DEFAULT,},
comment = {wxstc.wxSTC_C_COMMENT,
wxstc.wxSTC_C_COMMENTLINE,
wxstc.wxSTC_C_COMMENTDOC,
wxstc.wxSTC_C_COMMENTLINEDOC,
wxstc.wxSTC_C_COMMENTDOCKEYWORD,
wxstc.wxSTC_C_COMMENTDOCKEYWORDERROR,},
stringtxt = {wxstc.wxSTC_C_STRING,
wxstc.wxSTC_C_CHARACTER,
wxstc.wxSTC_C_UUID,},
stringeol = {wxstc.wxSTC_C_STRINGEOL,},
preprocessor= {wxstc.wxSTC_C_PREPROCESSOR,},
operator = {wxstc.wxSTC_C_OPERATOR,},
number = {wxstc.wxSTC_C_NUMBER,
wxstc.wxSTC_C_WORD},
keywords0 = {wxstc.wxSTC_C_WORD,},
keywords1 = {wxstc.wxSTC_C_WORD2,},
},
keywords = {
[[int uint uchar ushort float double size_t ptrdiff_t intptr_t uintptr_t
long ulong char short unsigned
float2 float4 float8 float16
double2 double4 double8 double16
char2 char4 char8 char16
uchar2 uchar4 uchar8 uchar16
short2 short4 short8 short16
ushort2 ushort4 ushort8 ushort16
int2 int4 int8 int16
uint2 uint4 uint8 uint16
long2 long4 long8 long16
ulong2 ulong4 ulong8 ulong16
half2 half4 half8 half16
void half bool
image2d_t image3d_t sampler_t event_t cl_image_format
struct typedef void const inline
return switch case for do while if else break continue volatile
CLK_A CLK_R CLK_RG CLK_RGB CLK_RGBA CLK_ARGB CLK_BGRA CLK_INTENSITY CLK_LUMINANCE
MAXFLOAT HUGE_VALF INFINITY NAN
CLK_LOCAL_MEM_FENCE CLK_GLOBAL_MEM_FENCE
CLK_SNORM_INT8
CLK_SNORM_INT16
CLK_UNORM_INT8
CLK_UNORM_INT16
CLK_UNORM_SHORT_565
CLK_UNORM_SHORT_555
CLK_UNORM_SHORT_101010
CLK_SIGNED_INT8
CLK_SIGNED_INT16
CLK_SIGNED_INT32
CLK_UNSIGNED_INT8
CLK_UNSIGNED_INT16
CLK_UNSIGNED_INT32
CLK_HALF_FLOAT
CLK_FLOAT
__FILE__ __LINE__ __OPENCL_VERSION__ __ENDIAN_LITTLE__
__ROUNDING_MODE__ __IMAGE_SUPPORT__ __FAST_RELAXED_MATH__
]],
[[__kernel kernel __attribute__ __read_only __write_only read_only write_only
__constant constant __local local __global global __private private
vec_type_hint work_group_size_hint reqd_work_group_size
aligned packed endian host device
async_work_group_copy wait_group_events prefetch
clamp min max degrees radians sign smoothstep step mix
mem_fence read_mem_fence write_mem_fence
cross prod distance dot length normalize fast_distance fast_length fast_normalize
get_image_width get_image_height get_image_depth
get_image_channel_data_type get_image_channel_order
get_image_dim
abs abs_diff add_sat clz hadd mad24 mad_hi mad_sat
mul24 mul_hi rhadd rotate sub_sat upsample
read_imagei write_imagei read_imageui write_imageui
read_imagef write_imagef
isequal isnotequal isgreater isgreaterequal isless islessequal islessgreater
isfinite isinf isnan isnormal isordered isunordered signbit any all bitselect select
acos acosh acospi asin asinh asinpi atan atan2 atanh atanpi atan2pi
cbrt ceil copysign cos half_cos native_cos cosh cospi half_divide native_divide
erf erfc exp half_exp native_exp exp2 half_exp2 native_exp2 exp10 half_exp10 native_exp10
expm1 fabs fdim floor fma fmax fmin fmod fract frexp hypot ilogb
ldexp lgamma lgamma_r log half_log native_log log2 half_log2 native_log2
log10 half_log10 native_log10 log1p logb mad modf nan nextafter
pow pown powr half_powr native_powr half_recip native_recip
remainder remquo rint round rootn rsqrt half_rsqrt native_rsqrt
sin half_sin native_sin sincos sinh sinpi sqrt half_sqrt native_sqrt
tan half_tan native_tan tanh tanpi tgamma trunc
barrier
vload2 vload4 vload8 vload16
vload_half vload_half2 vload_half4 vload_half8 vload_half16 vloada_half4 vloada_half8 vloada_half16
vstore2 vstore4 vstore8 vstore16
vstore_half vstore_half2 vstore_half4 vstore_half8 vstore_half16 vstorea_half4 vstorea_half8 vstorea_half16
get_global_id get_global_size get_group_id get_local_id get_local_size get_num_groups get_work_dim
x y z w
xxxx xxxy xxxz xxxw xxyx xxyy xxyz xxyw xxzx xxzy
xxzz xxzw xxwx xxwy xxwz xxww xyxx xyxy xyxz xyxw
xyyx xyyy xyyz xyyw xyzx xyzy xyzz xyzw xywx xywy
xywz xyww xzxx xzxy xzxz xzxw xzyx xzyy xzyz xzyw
xzzx xzzy xzzz xzzw xzwx xzwy xzwz xzww xwxx xwxy
xwxz xwxw xwyx xwyy xwyz xwyw xwzx xwzy xwzz xwzw
xwwx xwwy xwwz xwww yxxx yxxy yxxz yxxw yxyx yxyy
yxyz yxyw yxzx yxzy yxzz yxzw yxwx yxwy yxwz yxww
yyxx yyxy yyxz yyxw yyyx yyyy yyyz yyyw yyzx yyzy
yyzz yyzw yywx yywy yywz yyww yzxx yzxy yzxz yzxw
yzyx yzyy yzyz yzyw yzzx yzzy yzzz yzzw yzwx yzwy
yzwz yzww ywxx ywxy ywxz ywxw ywyx ywyy ywyz ywyw
ywzx ywzy ywzz ywzw ywwx ywwy ywwz ywww zxxx zxxy
zxxz zxxw zxyx zxyy zxyz zxyw zxzx zxzy zxzz zxzw
zxwx zxwy zxwz zxww zyxx zyxy zyxz zyxw zyyx zyyy
zyyz zyyw zyzx zyzy zyzz zyzw zywx zywy zywz zyww
zzxx zzxy zzxz zzxw zzyx zzyy zzyz zzyw zzzx zzzy
zzzz zzzw zzwx zzwy zzwz zzww zwxx zwxy zwxz zwxw
zwyx zwyy zwyz zwyw zwzx zwzy zwzz zwzw zwwx zwwy
zwwz zwww wxxx wxxy wxxz wxxw wxyx wxyy wxyz wxyw
wxzx wxzy wxzz wxzw wxwx wxwy wxwz wxww wyxx wyxy
wyxz wyxw wyyx wyyy wyyz wyyw wyzx wyzy wyzz wyzw
wywx wywy wywz wyww wzxx wzxy wzxz wzxw wzyx wzyy
wzyz wzyw wzzx wzzy wzzz wzzw wzwx wzwy wzwz wzww
wwxx wwxy wwxz wwxw wwyx wwyy wwyz wwyw wwzx wwzy
wwzz wwzw wwwx wwwy wwwz wwww xy xz yz xyz
xw yw xyw zw xzw yzw xyzw ]]..convout.." "..astypeout,
},
}

437
spec/ptx.lua Normal file
View File

@@ -0,0 +1,437 @@
-- author: Christoph Kubisch
---------------------------------------------------------
return {
exts = {"ptx",},
lexer = wxstc.wxSTC_LEX_CPP,
apitype = "ptx",
sep = "%.",
linecomment = "//",
isfndef = function(str)
local l
local s,e,cap = string.find(str,"^%s*([A-Za-z0-9_]+%s+[A-Za-z0-9_]+%s*%(.+%))")
if (not s) then
s,e,cap = string.find(str,"^%s*([A-Za-z0-9_]+%s+[A-Za-z0-9_]+)%s*%(")
end
if (cap and (string.find(cap,"^return") or string.find(cap,"else"))) then return end
return s,e,cap,l
end,
lexerstyleconvert = {
text = {wxstc.wxSTC_C_IDENTIFIER,
wxstc.wxSTC_C_VERBATIM,
wxstc.wxSTC_C_REGEX,
wxstc.wxSTC_C_REGEX,
wxstc.wxSTC_C_GLOBALCLASS,},
lexerdef = {wxstc.wxSTC_C_DEFAULT,},
comment = {wxstc.wxSTC_C_COMMENT,
wxstc.wxSTC_C_COMMENTLINE,
wxstc.wxSTC_C_COMMENTDOC,
wxstc.wxSTC_C_COMMENTLINEDOC,
wxstc.wxSTC_C_COMMENTDOCKEYWORD,
wxstc.wxSTC_C_COMMENTDOCKEYWORDERROR,},
stringtxt = {wxstc.wxSTC_C_STRING,
wxstc.wxSTC_C_CHARACTER,
wxstc.wxSTC_C_UUID,},
stringeol = {wxstc.wxSTC_C_STRINGEOL,},
preprocessor= {wxstc.wxSTC_C_PREPROCESSOR,},
operator = {wxstc.wxSTC_C_OPERATOR,},
number = {wxstc.wxSTC_C_NUMBER,
wxstc.wxSTC_C_WORD},
keywords0 = {wxstc.wxSTC_C_WORD,},
keywords1 = {wxstc.wxSTC_C_WORD2,},
},
keywords = {
[[
version
target
address_size
entry
func
branchtargets
calltargets
callprototype
maxnreg
maxntid
reqntid
minnctapersm
maxnctapersm
pragma
section
file
loc
extern
visible
pragma
align
file
maxntid
shared
branchtargets
func
minnctapersm
sreg
callprototype
global
param
target
calltargets
local
pragma
tex
const
loc
reg
version
entry
maxnctapersm
reqntid
visible
extern
maxnreg
section
s8
s16
s32
s64
u8
u16
u32
u64
f16
f32
f64
b8
b16
b32
b64
pred
rn
rz
rm
rp
rni
rzi
rmi
rpi
ca
cg
cs
lu
cv
wb
cg
cs
wt
texref
samplerref
surfref
sat
ftz
cc
hi
lo
wide
f4e
b4e
rc8
ecl
ecr
rc16
finite
infinite
number
notanumber
normal
subnormal
approx
full
eq
ne
lt
le
gt
ge
equ
neu
ltu
leu
gtu
geu
num
nan
ls
hs
volatile
v2
v4
L1
L2
1d
2d
3d
a1d
a2d
width
height
depth
channel_data_type
channel_order
normalized_coords
force_unnormalized_coords
filter_mode
addr_mode_0
addr_mode_1
addr_mode_2
trap
clamp
zero
all
any
uni
ballot
sync
arrive
red
cta
gl
sys
and
or
xor
cas
exch
add
inc
dec
min
max
b0
b1
b2
b3
h0
h1
wrap
shr7
shr15
byte
4byte
quad
4byte
quad
b8
b32
b64
b32
b64
]],
-- functions
[[
add
sub
add.cc
addc
sub.cc
subc
mul
mad
mul24
mad24
sad
div
rem
abs
neg
min
max
popc
clz
bfind
brev
bfe
bfi
prmt
rcp
sqrt
rsqrt
sin
cos
lg2
ex2
fma
set
setp
selp
slct
and
or
xor
not
cnot
shl
shr
mov
ld
ldu
st
prefetch
prefetchu
isspacep
cvta
cvt
tex
tld4
txq
suld
sust
sured
suq
bra
call
ret
exit
bar
membar
atom
red
vote
vadd
vsub
vabsdiff
vmin
vmax
vshl
vshr
vmad
vset
trap
brkpt
pmevent
%clock
%laneid
%lanemask_gt
%pm0
%pm1
%pm2
%pm3
%clock64
%lanemask_eq
%nctaid
%smid
%ctaid
%lanemask_le
%ntid
%tid
%envreg0
%envreg1
%envreg2
%envreg3
%envreg4
%envreg5
%envreg6
%envreg7
%envreg8
%envreg9
%envreg10
%envreg11
%envreg12
%envreg13
%envreg14
%envreg15
%envreg16
%envreg17
%envreg18
%envreg19
%envreg20
%envreg21
%envreg22
%envreg23
%envreg24
%envreg25
%envreg26
%envreg27
%envreg28
%envreg29
%envreg30
%envreg31
%lanemask_lt
%nsmid
%warpid
%gridid
%lanemask_ge
%nwarpid
WARP_SZ
nearest
linear
wrap
mirror
clamp_ogl
clamp_to_edge
clamp_to_border
sm_20
sm_10
sm_11
sm_12
sm_13
texmode_unified
texmode_independent
map_f64_to_f32
]],
},
}

View File

@@ -2,87 +2,86 @@
---------------------------------------------------------
return {
exts = {"sql"},
lexer = wxstc.wxSTC_LEX_LUA,
apitype = "sql",
linecomment = "--",
isfncall = function(str)
return string.find(str,"([A-Za-z0-9_]+)%s*%(")
end,
lexerstyleconvert = {
text = {wxstc.wxSTC_LUA_IDENTIFIER,},
lexerdef = {wxstc.wxSTC_LUA_DEFAULT,},
comment = {wxstc.wxSTC_LUA_COMMENT,
wxstc.wxSTC_LUA_COMMENTLINE,
wxstc.wxSTC_LUA_COMMENTDOC,},
stringtxt = {wxstc.wxSTC_LUA_STRING,
wxstc.wxSTC_LUA_CHARACTER,
wxstc.wxSTC_LUA_LITERALSTRING,},
stringeol = {wxstc.wxSTC_LUA_STRINGEOL,},
preprocessor= {wxstc.wxSTC_LUA_PREPROCESSOR,},
operator = {wxstc.wxSTC_LUA_OPERATOR,},
number = {wxstc.wxSTC_LUA_NUMBER,},
keywords0 = {wxstc.wxSTC_LUA_WORD,},
keywords1 = {wxstc.wxSTC_LUA_WORD2,},
keywords2 = {wxstc.wxSTC_LUA_WORD3,},
keywords3 = {wxstc.wxSTC_LUA_WORD4,},
keywords4 = {wxstc.wxSTC_LUA_WORD5,},
keywords5 = {wxstc.wxSTC_LUA_WORD6,},
keywords6 = {wxstc.wxSTC_LUA_WORD7,},
keywords7 = {wxstc.wxSTC_LUA_WORD8,},
},
keywords = {
[[ SELECT FROM CREATE TABLE WHERE ORDER BY CASE
WHEN CHECK CONSTRAINT PRIMARY AUTOINCREMENT
INSERT INTO DELETE DROP DISTINCT GROUP IS DEFAULT
BEGIN TRANSACTION COMMIT KEY REFERENCES UNIQUE INDEX ON SET RESTRICT
CASCADE ]],
-- javascript keywords
[[ NULL]],
[[ TEXT BOOLEAN INTEGER]]
},
exts = {"sql"},
lexer = wxstc.wxSTC_LEX_LUA,
apitype = "sql",
linecomment = "--",
isfncall = function(str)
return string.find(str,"([A-Za-z0-9_]+)%s*%(")
end,
lexerstyleconvert = {
text = {wxstc.wxSTC_LUA_IDENTIFIER,},
lexerdef = {wxstc.wxSTC_LUA_DEFAULT,},
comment = {wxstc.wxSTC_LUA_COMMENT,
wxstc.wxSTC_LUA_COMMENTLINE,
wxstc.wxSTC_LUA_COMMENTDOC,},
stringtxt = {wxstc.wxSTC_LUA_STRING,
wxstc.wxSTC_LUA_CHARACTER,
wxstc.wxSTC_LUA_LITERALSTRING,},
stringeol = {wxstc.wxSTC_LUA_STRINGEOL,},
preprocessor= {wxstc.wxSTC_LUA_PREPROCESSOR,},
operator = {wxstc.wxSTC_LUA_OPERATOR,},
number = {wxstc.wxSTC_LUA_NUMBER,},
keywords0 = {wxstc.wxSTC_LUA_WORD,},
keywords1 = {wxstc.wxSTC_LUA_WORD2,},
keywords2 = {wxstc.wxSTC_LUA_WORD3,},
keywords3 = {wxstc.wxSTC_LUA_WORD4,},
keywords4 = {wxstc.wxSTC_LUA_WORD5,},
keywords5 = {wxstc.wxSTC_LUA_WORD6,},
keywords6 = {wxstc.wxSTC_LUA_WORD7,},
keywords7 = {wxstc.wxSTC_LUA_WORD8,},
},
keywords = {
[[ SELECT FROM CREATE TABLE WHERE ORDER BY CASE
WHEN CHECK CONSTRAINT PRIMARY AUTOINCREMENT
INSERT INTO DELETE DROP DISTINCT GROUP IS DEFAULT
BEGIN TRANSACTION COMMIT KEY REFERENCES UNIQUE INDEX ON SET RESTRICT
CASCADE ]],
-- javascript keywords
[[ NULL]],
[[ TEXT BOOLEAN INTEGER]]
},
}
--[==[return {
exts = {"sql"},
lexer = wxstc.wxSTC_LEX_SQL,
apitype = "sql",
linecomment = "--",
stylingbits = 5,
lexerstyleconvert = {
text = {wx.wxSTC_SQL_DEFAULT},
comment = {wx.wxSTC_SQL_COMMENT,wx.wxSTC_SQL_COMMENTLINE},
stringeol = {},
number = {wx.wxSTC_SQL_NUMBER},
stringtxt = {},
lexerdef= {},
keywords0 = {wx.wxSTC_SQL_IDENTIFIER, wx.wxSTC_SQL_QUOTEDIDENTIFIER},
keywords1 = {wx.wxSTC_SQL_STRING},
keywords2 = {wx.wxSTC_SQL_COMMENTDOC,wx.wxSTC_SQL_COMMENTDOCKEYWORD},
keywords3 = {wx.wxSTC_SQL_COMMENTDOCKEYWORDERROR,wx.wxSTC_SQL_COMMENTLINEDOC},
keywords4 = {wx.wxSTC_SQL_WORD,wx.wxSTC_SQL_WORD2,},
keywords5 = {wx.wxSTC_SQL_USER1,wx.wxSTC_SQL_USER2,wx.wxSTC_SQL_USER3,wx.wxSTC_SQL_USER4},
keywords6 = {},
keywords7 = {},
preprocessor= {},
},
keywords = {
-- HTML tags and attributes
[[ SELECT FROM CREATE TABLE WHERE ORDER BY CASE
WHEN CHECK CONSTRAINT PRIMARY INTEGER AUTOINCREMENT
INSERT INTO DELETE DROP DISTINCT GROUP IS DEFAULT]],
-- javascript keywords
[[ NULL]]
},
--[==[
return {
exts = {"sql"},
lexer = wxstc.wxSTC_LEX_SQL,
apitype = "sql",
linecomment = "--",
stylingbits = 5,
lexerstyleconvert = {
text = {wx.wxSTC_SQL_DEFAULT},
comment = {wx.wxSTC_SQL_COMMENT,wx.wxSTC_SQL_COMMENTLINE},
stringeol = {},
number = {wx.wxSTC_SQL_NUMBER},
stringtxt = {},
lexerdef= {},
keywords0 = {wx.wxSTC_SQL_IDENTIFIER, wx.wxSTC_SQL_QUOTEDIDENTIFIER},
keywords1 = {wx.wxSTC_SQL_STRING},
keywords2 = {wx.wxSTC_SQL_COMMENTDOC,wx.wxSTC_SQL_COMMENTDOCKEYWORD},
keywords3 = {wx.wxSTC_SQL_COMMENTDOCKEYWORDERROR,wx.wxSTC_SQL_COMMENTLINEDOC},
keywords4 = {wx.wxSTC_SQL_WORD,wx.wxSTC_SQL_WORD2,},
keywords5 = {wx.wxSTC_SQL_USER1,wx.wxSTC_SQL_USER2,wx.wxSTC_SQL_USER3,wx.wxSTC_SQL_USER4},
keywords6 = {},
keywords7 = {},
preprocessor= {},
},
}]==]
keywords = {
-- HTML tags and attributes
[[ SELECT FROM CREATE TABLE WHERE ORDER BY CASE
WHEN CHECK CONSTRAINT PRIMARY INTEGER AUTOINCREMENT
INSERT INTO DELETE DROP DISTINCT GROUP IS DEFAULT]],
-- javascript keywords
[[ NULL]]
},
}
]==]

View File

@@ -1,10 +1,9 @@
-- authors: Luxinia Dev (Eike Decker & Christoph Kubisch)
---------------------------------------------------------
return {
exts = {"txt"},
--lexer = wxstc.wxSTC_LEX_POV,
--apitype = "luxres",
linecomment = ">",
}
-- authors: Luxinia Dev (Eike Decker & Christoph Kubisch)
---------------------------------------------------------
return {
exts = {"txt"},
--lexer = wxstc.wxSTC_LEX_POV,
--apitype = "luxres",
linecomment = ">",
}

317
src/defs.lua Normal file
View File

@@ -0,0 +1,317 @@
-- About
-- ----------------------------------------------------
-- This file contains lua table definitons used by
-- automatic loaded files, not part of the
-- editor source.
--
-- /<app>/config.lua
-- /cfg/user.lua
-- /interpreters/*.lua
-- /specs/*.lua
-- /tools/*.lua
-- /api/<apitype>/*.lua
-- style definition
-- ----------------------------------------------------
-- all entries are optional
stattr = {
fg = {r,g,b}, -- foreground color 0-255
bg = {r,g,b}, -- background color
i = false, -- italic
b = false, -- bold
u = false, -- underline
fill = true, -- fill to lineend
-- fn = "Lucida Console", -- font Face Name
-- fx = 11, -- font size
-- hs = true or {r,g,b}, -- turn hotspot on
-- use the specified color as activeForeground
-- use "hs = true", to turn it on without changing the color
-- HotspotActiveUnderline and HotspotSingleLine are on automatically
-- v = true, -- visibility for symbols of the current style
}
style = {
-- lexer specific (inherit fg/bg from text)
lexerdef = stattr,
comment = stattr,
stringtxt = stattr,
stringeol = stattr,
preprocessor = stattr,
operator = stattr,
number = stattr,
keywords0 = stattr,
keywords1 = stattr,
keywords2 = stattr,
keywords3 = stattr,
keywords4 = stattr,
keywords5 = stattr,
keywords6 = stattr,
keywords7 = stattr,
-- common (inherit fg/bg from text)
text = stattr,
linenumber = stattr,
bracematch = stattr,
bracemiss = stattr,
escapechar = stattr,
indent = stattr,
calltip = stattr,
-- common special (need custom fg & bg )
calltipbg = nil,
sel = nil,
caret = nil,
caretlinebg = nil,
fold = nil,
whitespace = nil,
-- special, functioncall indicator
fncall = {
fg = {r,g,b},
st = wxstc.wxSTC_INDIC_BOX,
},
}
-- config definition
-- ----------------------------------------------------
-- tables must exist
-- content is optional
-- config is loaded into existing config table
config = {
appname = "estrela", -- by default the launcher name
path = {
-- path for tools/interpreters
luxinia = "C:/luxbin/",
-- path to luxinia exe
projectdir = "",
-- the project directory, used by
-- some tools/interpreters
},
editor = {
fontname = "Courier New",
-- default font
fontsize = 10,
-- defailt size
caretline = true,
-- show active line
-- input/output filtering of strings
-- current filters "GermanUtf8Ascii"
iofilter = nil,
-- use indicator to show function calls
-- if spec allows
showfncall = true,
tabwidth = 4,
usetabs = true, -- if false then spaces are used
usewrap = true, -- if true then the text is wrapped in the editor
whitespace = false,
autotabs = true, -- if true test for tabs after file load,
-- sets "usetabs" to true for this file
},
debugger = {
verbose = false,
}
outputshell = {
-- output and shell settings
fontname = "Courier New",
-- default font
fontsize = 10,
-- defult size
}
styles = {},
-- styles table as above for editor
stylesoutshell = {},
-- styles for output/shell
interpreter = "EstrelaEditor",
-- the default "project" lua interpreter
autocomplete = true,
-- whether autocomplete is on by default
acandtip = {
shorttip = false,
-- tooltips are compact during typing
nodynwords = false,
-- no dynamic words (user entered words)
ignorecase = false,
-- ignores case when performing comparison with autocomplete list
strategy = 0,
-- 0: is string comparison
-- 1: substring leading characters (camel case or _ separated)
-- 2: leading + any correctly ordered fragments (default)
}
savebak = false,
-- if bak files are created on save
filehistorylength = 20,
-- historylength for files
projecthistorylength = 15,
-- historylength for project directories
singleinstance = true,
-- if true creates a UDP server to exchange messages
-- for loading commandline passed files
singleinstanceport = 0xe493,
-- UDP port for single instance communication
}
-- application engine
-- ----------------------------------------------------
app = {
preinit = function() end, -- post spec/tool loading, but prior subsystems/ui generation
postinit = function() end, -- post init, prior starting mainloop
loadfilters = {
tools = function(file) return true end,
specs = function(file) return true end,
interpreters = function(file) return true end,
}
stringtable = { -- optional entries uses defaults otherwise
editor = nil, statuswelcome = nil,
-- ...
}
}
-- api definition
-- ----------------------------------------------------
-- hierarchy encoded into children
api = {
-- global space words, e.g "table"
["blah"] = {
-- "function", "class", "keyword", "value", "lib"
type = "function",
description = "this does something",
-- value and function:
valuetype = "api.ClassName",
-- function:
args = "(blah,blubb)",
returns = "(foo)",
-- autogenerated post load:
-- concated hierarchy name (e.g. "lib.class")
classname = "blah",
-- children in the class hierarchy
childs = {
--.. recursive
}
},
["blubb"] = {
--...
},
}
-- spec definition
-- ----------------------------------------------------
-- all entries are optional
spec = {
exts = {"ext","ext2",..},
-- compatible extensions
lexer = wxstc.wxSTC_LEX_LUA,
-- scintilla lexer
lexerstyleconvert = {
-- table mapping each styles to
-- appropriate lexer id
stringeol = {wxstc.wxSTC_LUA_STRINGEOL,},
-- ...
}
linecomment = "//",
-- string for linecomments
sep = "[%.:]",
-- class.function separator match string,
-- e.g in lua both . and : are allowed
-- default is "\1" which should yield no matches
-- and therefore disable class.func type autocompletion
isfncall = function(str) return from,to end
-- function that detects positions for a substring that
-- stands for a functioncall, ie " call(..)" -> 2,5
apitype = "api",
-- which sub directory of "api" is relevant
-- api files handle autocomplete and tooltips
-- api won't affect syntax coloring
keywords = {
-- up to 8 strings containing space separated keywords
-- used by the lexer for coloring (NOT for autocomplete).
-- however each lexer supports varying amount
-- of keyword types
"foo bar word",
"more words",
}
}
-- tool definition
-- ----------------------------------------------------
-- main entries are optional
tool = {
fninit = function(frame,menubar) end,
-- guarantees that ide is initialized
-- can be used for init
-- and adding custom menu
exec = {
-- quick exec action, listed under "Tools" menu
name = "",
description = "",
fn = function(wxfilename,projectdir) end,
}
}
-- debuginterface definition
-- ----------------------------------------------------
debuginterface = {
update = function(self) end, -- run in idle when active
close = function(self) end, -- run when closed
-- following are "debugging" actions and must return
-- error, running, [filePath, fileLine]
run = function(self) end,
step = function(self) end,
over = function(self) end,
out = function(self) end,
terminate = function(self) end,
breaknow = function(self) end,
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
}
-- 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
hasdebugger = false, -- if debugging is available
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,470 +1,507 @@
-- authors: Lomtik Software (J. Winwood & John Labenski)
-- Luxinia Dev (Eike Decker & Christoph Kubisch)
---------------------------------------------------------
local ide = ide
local frame = ide.frame
local splitter = ide.frame.vsplitter.splitter
local notebook = splitter.notebook
local openDocuments = ide.openDocuments
function NewFile(event)
local editor = CreateEditor("untitled.lua")
SetupKeywords(editor, "lua")
end
-- Find an editor page that hasn't been used at all, eg. an untouched NewFile()
local function findDocumentToReuse()
local editor = nil
for id, document in pairs(openDocuments) do
if (document.editor:GetLength() == 0) and
(not document.isModified) and (not document.filePath) and
not (document.editor:GetReadOnly() == true) then
editor = document.editor
break
end
end
return editor
end
function LoadFile(filePath, editor, file_must_exist)
filePath = filePath:gsub("\\","/")
-- prevent files from being reopened again
if (not editor) then
for id, doc in pairs(openDocuments) do
if doc.filePath == filePath then
notebook:SetSelection(doc.index)
return doc.editor
end
end
end
-- if not opened yet, try open now
local file_text = ""
local handle = io.open(filePath, "rb")
if handle then
file_text = handle:read("*a")
if GetConfigIOFilter("input") then
file_text = GetConfigIOFilter("input")(filePath,file_text)
end
handle:close()
elseif file_must_exist then
return nil
end
if not editor then
editor = findDocumentToReuse()
end
if not editor then
editor = CreateEditor(wx.wxFileName(filePath):GetFullName() or "untitled.lua")
end
editor:Clear()
editor:ClearAll()
SetupKeywords(editor, GetFileExt(filePath))
editor:MarkerDeleteAll(BREAKPOINT_MARKER)
editor:MarkerDeleteAll(CURRENT_LINE_MARKER)
editor:AppendText(file_text)
if (ide.config.editor.autotabs) then
local found = string.find(file_text,"\t") ~= nil
editor:SetUseTabs(found)
end
editor:EmptyUndoBuffer()
local id = editor:GetId()
openDocuments[id].filePath = filePath
openDocuments[id].fileName = wx.wxFileName(filePath):GetFullName()
openDocuments[id].modTime = GetFileModTime(filePath)
SetDocumentModified(id, false)
editor:Colourise(0, -1)
AddDynamicWords(editor)
IndicateFunctions(editor)
SettingsAppendFileToHistory(filePath)
return editor
end
local function getExtsString()
local knownexts = ""
for i,spec in pairs(ide.specs) do
if (spec.exts) then
for n,ext in ipairs(spec.exts) do
knownexts = knownexts.."*."..ext..";"
end
end
end
knownexts = knownexts:len() > 0 and knownexts:sub(1,-2) or nil
local exts = knownexts and "Known Files ("..knownexts..")|"..knownexts.."|" or ""
exts = exts.."All files (*)|*"
return exts
end
function OpenFile(event)
local exts = getExtsString()
local fileDialog = wx.wxFileDialog(ide.frame, "Open file",
"",
"",
exts,
wx.wxOPEN + wx.wxFILE_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().."'.",
"wxLua Error",
wx.wxOK + wx.wxCENTRE, ide.frame)
end
end
fileDialog:Destroy()
end
-- save the file to filePath or if filePath is nil then call SaveFileAs
function SaveFile(editor, filePath)
if not filePath then
return SaveFileAs(editor)
else
filePath = filePath:gsub("\\","/")
if (ide.config.savebak) then
local backPath = filePath..".bak"
os.remove(backPath)
os.rename(filePath, backPath)
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()
editor:SetSavePoint()
local id = editor:GetId()
openDocuments[id].filePath = filePath
openDocuments[id].fileName = wx.wxFileName(filePath):GetFullName()
openDocuments[id].modTime = GetFileModTime(filePath)
SetDocumentModified(id, false)
return true
else
wx.wxMessageBox("Unable to save file '"..filePath.."'.",
"wxLua Error Saving",
wx.wxOK + wx.wxCENTRE, ide.frame)
end
end
return false
end
function SaveFileAs(editor)
local id = editor:GetId()
local saved = false
local filePath = openDocuments[id].filePath
if (not filePath) then
filePath = GetFileTreeDir()
filePath = (filePath or "").."untitled"
end
local fn = wx.wxFileName(filePath)
fn:Normalize() -- want absolute path for dialog
local exts = getExtsString()
local fileDialog = wx.wxFileDialog(ide.frame, "Save file as",
fn:GetPath(wx.wxPATH_GET_VOLUME),
fn:GetFullName(),
exts,
wx.wxSAVE)
if fileDialog:ShowModal() == wx.wxID_OK then
local filePath = fileDialog:GetPath()
if SaveFile(editor, filePath) then
SetupKeywords(editor, GetFileExt(filePath))
IndicateFunctions(editor)
saved = true
end
end
fileDialog:Destroy()
return saved
end
function SaveAll()
for id, document in pairs(openDocuments) do
local editor = document.editor
local filePath = document.filePath
if document.isModified then
SaveFile(editor, filePath) -- will call SaveFileAs if necessary
end
end
end
function RemovePage(index)
local prevIndex = nil
local nextIndex = nil
--local newOpenDocuments = {}
local delid = nil
for id, document in pairs(openDocuments) do
if document.index < index then
--newOpenDocuments[id] = document
prevIndex = document.index
elseif document.index == index then
delid = id
document.editor:Destroy()
elseif document.index > index then
document.index = document.index - 1
if nextIndex == nil then
nextIndex = document.index
end
--newOpenDocuments[id] = document
end
end
if (delid) then
openDocuments[delid] = nil
end
notebook:RemovePage(index)
if nextIndex then
notebook:SetSelection(nextIndex)
elseif prevIndex then
notebook:SetSelection(prevIndex)
end
SetEditorSelection(nil) -- will use notebook GetSelection to update
end
-- Show a dialog to save a file before closing editor.
-- returns wxID_YES, wxID_NO, or wxID_CANCEL if allow_cancel
function SaveModifiedDialog(editor, allow_cancel)
local result = wx.wxID_NO
local id = editor:GetId()
local document = openDocuments[id]
local filePath = document.filePath
local fileName = document.fileName
if document.isModified then
local message
if fileName then
message = "Save changes to '"..fileName.."' before exiting?"
else
message = "Save changes to 'untitled' before exiting?"
end
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,
"Save Changes?",
dlg_styles)
result = dialog:ShowModal()
dialog:Destroy()
if result == wx.wxID_YES then
SaveFile(editor, filePath)
end
end
return result
end
function SaveOnExit(allow_cancel)
for id, document in pairs(openDocuments) do
if (SaveModifiedDialog(document.editor, allow_cancel) == wx.wxID_CANCEL) then
return false
end
document.isModified = false
end
return true
end
function FoldSome()
local editor = GetEditor()
editor:Colourise(0, -1) -- update doc's folding info
local visible, baseFound, expanded, folded
for ln = 2, editor.LineCount - 1 do
local foldRaw = editor:GetFoldLevel(ln)
local foldLvl = math.mod(foldRaw, 4096)
local foldHdr = math.mod(math.floor(foldRaw / 8192), 2) == 1
if not baseFound and (foldLvl == wxstc.wxSTC_FOLDLEVELBASE) then
baseFound = true
visible = editor:GetLineVisible(ln)
end
if foldHdr then
if editor:GetFoldExpanded(ln) then
expanded = true
else
folded = true
end
end
if expanded and folded and baseFound then break end
end
local show = not visible or (not baseFound and expanded) or (expanded and folded)
local hide = visible and folded
if show then
editor:ShowLines(1, editor.LineCount-1)
end
for ln = 1, editor.LineCount - 1 do
local foldRaw = editor:GetFoldLevel(ln)
local foldLvl = math.mod(foldRaw, 4096)
local foldHdr = math.mod(math.floor(foldRaw / 8192), 2) == 1
if show then
if foldHdr then
if not editor:GetFoldExpanded(ln) then editor:ToggleFold(ln) end
end
elseif hide and (foldLvl == wxstc.wxSTC_FOLDLEVELBASE) then
if not foldHdr then
editor:HideLines(ln, ln)
end
elseif foldHdr then
if editor:GetFoldExpanded(ln) then
editor:ToggleFold(ln)
end
end
end
editor:EnsureCaretVisible()
end
function EnsureRangeVisible(posStart, posEnd)
local editor = GetEditor()
if posStart > posEnd then
posStart, posEnd = posEnd, posStart
end
local lineStart = editor:LineFromPosition(posStart)
local lineEnd = editor:LineFromPosition(posEnd)
for line = lineStart, lineEnd do
editor:EnsureVisibleEnforcePolicy(line)
end
end
function SetAllEditorsReadOnly(enable)
for id, document in pairs(openDocuments) do
local editor = document.editor
editor:SetReadOnly(enable)
end
end
-----------------
-- Debug related
function ClearAllCurrentLineMarkers()
for id, document in pairs(openDocuments) do
local editor = document.editor
editor:MarkerDeleteAll(CURRENT_LINE_MARKER)
end
end
function CompileProgram(editor)
local editorText = editor:GetText()
local id = editor:GetId()
local filePath = MakeDebugFileName(editor, openDocuments[id].filePath)
local ret, errMsg, line_num = wxlua.CompileLuaScript(editorText, filePath)
if ide.frame.menuBar:IsChecked(ID_CLEAROUTPUT) then
ClearOutput()
end
if line_num > -1 then
DisplayOutput("Compilation error on line number :"..tostring(line_num).."\n"..errMsg.."\n")
editor:GotoLine(line_num-1)
else
DisplayOutput("Compilation successful.\n")
end
return line_num == -1 -- return true if it compiled ok
end
------------------
-- Save & Close
function SaveIfModified(editor)
local id = editor:GetId()
if openDocuments[id].isModified then
local saved = false
if not openDocuments[id].filePath then
local ret = wx.wxMessageBox("You must save the program before running it.\nPress cancel to abort running.",
"Save file?", wx.wxOK + wx.wxCANCEL + wx.wxCENTRE, ide.frame)
if ret == wx.wxOK then
saved = SaveFileAs(editor)
end
else
saved = SaveFile(editor, openDocuments[id].filePath)
end
if saved then
openDocuments[id].isModified = false
else
return false -- not saved
end
end
return true -- saved
end
function GetOpenFiles()
local opendocs = {}
for id, document in pairs(ide.openDocuments) do
if (document.filePath) then
local wxfname = wx.wxFileName(document.filePath)
wxfname:Normalize()
table.insert(opendocs,{fname=wxfname:GetFullPath(),id=document.index,
cursorpos = document.editor:GetCurrentPos()})
end
end
-- to keep tab order
table.sort(opendocs,function(a,b) return (a.id < b.id) end)
local openfiles = {}
for i,doc in ipairs(opendocs) do
table.insert(openfiles,{filename = doc.fname, cursorpos = doc.cursorpos} )
end
local id = GetEditor()
id = id and id:GetId()
return openfiles, id and openDocuments[id].index or 0
end
function SetOpenFiles(nametab,index)
for i,doc in ipairs(nametab) do
local editor = LoadFile(doc.filename,nil,true)
if editor then
editor:SetCurrentPos(doc.cursorpos or 0)
editor:SetSelectionStart(doc.cursorpos or 0)
editor:SetSelectionEnd(doc.cursorpos or 0)
editor:EnsureCaretVisible()
end
end
notebook:SetSelection(index or 0)
end
function CloseWindow(event)
exitingProgram = true -- don't handle focus events
if not SaveOnExit(event:CanVeto()) then
event:Veto()
exitingProgram = false
return
end
SettingsSaveProjectSession(GetProjects())
SettingsSaveFileSession(GetOpenFiles())
SettingsSaveView()
SettingsSaveFramePosition(ide.frame, "MainFrame")
SettingsSaveEditorSettings()
CloseWatchWindow()
ide.settings:delete() -- always delete the config
event:Skip()
end
frame:Connect(wx.wxEVT_CLOSE_WINDOW, CloseWindow)
-- authors: Lomtik Software (J. Winwood & John Labenski)
-- Luxinia Dev (Eike Decker & Christoph Kubisch)
---------------------------------------------------------
local ide = ide
local frame = ide.frame
local notebook = frame.notebook
local openDocuments = ide.openDocuments
local uimgr = frame.uimgr
function NewFile(event)
local editor = CreateEditor("untitled.lua")
SetupKeywords(editor, "lua")
end
-- Find an editor page that hasn't been used at all, eg. an untouched NewFile()
local function findDocumentToReuse()
local editor = nil
for id, document in pairs(openDocuments) do
if (document.editor:GetLength() == 0) and
(not document.isModified) and (not document.filePath) and
not (document.editor:GetReadOnly() == true) then
editor = document.editor
break
end
end
return editor
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
for id, doc in pairs(openDocuments) do
local docName = doc.filePath and string.lower(string.gsub(doc.filePath, "\\", "/"))
if cmpName == docName then
notebook:SetSelection(doc.index)
return doc.editor
end
end
end
-- if not opened yet, try open now
local file_text = ""
local handle = io.open(filePath, "rb")
if handle then
file_text = handle:read("*a")
if GetConfigIOFilter("input") then
file_text = GetConfigIOFilter("input")(filePath,file_text)
end
handle:close()
elseif file_must_exist then
return nil
end
if not editor then
editor = findDocumentToReuse()
end
if not editor then
editor = CreateEditor(wx.wxFileName(filePath):GetFullName() or "untitled.lua")
end
editor:Clear()
editor:ClearAll()
SetupKeywords(editor, GetFileExt(filePath))
editor:MarkerDeleteAll(BREAKPOINT_MARKER)
editor:MarkerDeleteAll(CURRENT_LINE_MARKER)
editor:AppendText(file_text)
if (ide.config.editor.autotabs) then
local found = string.find(file_text,"\t") ~= nil
editor:SetUseTabs(found)
end
editor:EmptyUndoBuffer()
local id = editor:GetId()
openDocuments[id].filePath = filePath
openDocuments[id].fileName = wx.wxFileName(filePath):GetFullName()
openDocuments[id].modTime = GetFileModTime(filePath)
SetDocumentModified(id, false)
editor:Colourise(0, -1)
IndicateFunctions(editor)
SettingsAppendFileToHistory(filePath)
SetEditorSelection(nil)
return editor
end
local function getExtsString()
local knownexts = ""
for i,spec in pairs(ide.specs) do
if (spec.exts) then
for n,ext in ipairs(spec.exts) do
knownexts = knownexts.."*."..ext..";"
end
end
end
knownexts = knownexts:len() > 0 and knownexts:sub(1,-2) or nil
local exts = knownexts and "Known Files ("..knownexts..")|"..knownexts.."|" or ""
exts = exts.."All files (*)|*"
return exts
end
function OpenFile(event)
local exts = getExtsString()
local fileDialog = wx.wxFileDialog(ide.frame, "Open file",
"",
"",
exts,
wx.wxOPEN + wx.wxFILE_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().."'.",
"Error",
wx.wxOK + wx.wxCENTRE, ide.frame)
end
end
fileDialog:Destroy()
end
-- save the file to filePath or if filePath is nil then call SaveFileAs
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)
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()
editor:SetSavePoint()
local id = editor:GetId()
openDocuments[id].filePath = filePath
openDocuments[id].fileName = wx.wxFileName(filePath):GetFullName()
openDocuments[id].modTime = GetFileModTime(filePath)
SetDocumentModified(id, false)
return true
else
wx.wxMessageBox("Unable to save file '"..filePath.."'.",
"Error",
wx.wxOK + wx.wxCENTRE, ide.frame)
end
end
return false
end
function SaveFileAs(editor)
local id = editor:GetId()
local saved = false
local filePath = openDocuments[id].filePath
if (not filePath) then
filePath = FileTreeGetDir()
filePath = (filePath or "").."untitled"
end
local fn = wx.wxFileName(filePath)
fn:Normalize() -- want absolute path for dialog
local exts = getExtsString()
local fileDialog = wx.wxFileDialog(ide.frame, "Save file as",
fn:GetPath(wx.wxPATH_GET_VOLUME),
fn:GetFullName(),
exts,
wx.wxSAVE)
if fileDialog:ShowModal() == wx.wxID_OK then
local filePath = fileDialog:GetPath()
if SaveFile(editor, filePath) then
SetupKeywords(editor, GetFileExt(filePath))
IndicateFunctions(editor)
if MarkupStyle then MarkupStyle(editor) end
saved = true
end
end
fileDialog:Destroy()
return saved
end
function SaveAll()
for id, document in pairs(openDocuments) do
local editor = document.editor
local filePath = document.filePath
if document.isModified then
SaveFile(editor, filePath) -- will call SaveFileAs if necessary
end
end
end
local function removePage(index)
local prevIndex = nil
local nextIndex = nil
-- try to preserve old selection
local selectIndex = notebook:GetSelection()
selectIndex = selectIndex ~= index and selectIndex
local delid = nil
for id, document in pairsSorted(openDocuments,
function(a, b) -- sort by document index
return openDocuments[a].index < openDocuments[b].index
end) do
local wasselected = document.index == selectIndex
if document.index < index then
prevIndex = document.index
elseif document.index == index then
delid = id
document.editor:Destroy()
elseif document.index > index then
document.index = document.index - 1
if nextIndex == nil then
nextIndex = document.index
end
end
if (wasselected) then
selectIndex = document.index
end
end
if (delid) then
openDocuments[delid] = nil
end
notebook:RemovePage(index)
if selectIndex then
notebook:SetSelection(selectIndex)
elseif nextIndex then
notebook:SetSelection(nextIndex)
elseif prevIndex then
notebook:SetSelection(prevIndex)
end
SetEditorSelection(nil) -- will use notebook GetSelection to update
end
function ClosePage(selection)
local editor = GetEditor(selection)
local id = editor:GetId()
if SaveModifiedDialog(editor, true) ~= wx.wxID_CANCEL then
DynamicWordsRemoveAll(editor)
removePage(ide.openDocuments[id].index)
end
end
-- Show a dialog to save a file before closing editor.
-- returns wxID_YES, wxID_NO, or wxID_CANCEL if allow_cancel
function SaveModifiedDialog(editor, allow_cancel)
local result = wx.wxID_NO
local id = editor:GetId()
local document = openDocuments[id]
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 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,
"Save Changes?",
dlg_styles)
result = dialog:ShowModal()
dialog:Destroy()
if result == wx.wxID_YES then
if not SaveFile(editor, filePath) then
return wx.wxID_CANCEL -- cancel if canceled save dialog
end
end
end
return result
end
function SaveOnExit(allow_cancel)
for id, document in pairs(openDocuments) do
if (SaveModifiedDialog(document.editor, allow_cancel) == wx.wxID_CANCEL) then
return false
end
document.isModified = false
end
return true
end
function FoldSome()
local editor = GetEditor()
editor:Colourise(0, -1) -- update doc's folding info
local visible, baseFound, expanded, folded
for ln = 2, editor.LineCount - 1 do
local foldRaw = editor:GetFoldLevel(ln)
local foldLvl = math.mod(foldRaw, 4096)
local foldHdr = math.mod(math.floor(foldRaw / 8192), 2) == 1
if not baseFound and (foldLvl == wxstc.wxSTC_FOLDLEVELBASE) then
baseFound = true
visible = editor:GetLineVisible(ln)
end
if foldHdr then
if editor:GetFoldExpanded(ln) then
expanded = true
else
folded = true
end
end
if expanded and folded and baseFound then break end
end
local show = not visible or (not baseFound and expanded) or (expanded and folded)
local hide = visible and folded
if show then
editor:ShowLines(1, editor.LineCount-1)
end
for ln = 1, editor.LineCount - 1 do
local foldRaw = editor:GetFoldLevel(ln)
local foldLvl = math.mod(foldRaw, 4096)
local foldHdr = math.mod(math.floor(foldRaw / 8192), 2) == 1
if show then
if foldHdr then
if not editor:GetFoldExpanded(ln) then editor:ToggleFold(ln) end
end
elseif hide and (foldLvl == wxstc.wxSTC_FOLDLEVELBASE) then
if not foldHdr then
editor:HideLines(ln, ln)
end
elseif foldHdr then
if editor:GetFoldExpanded(ln) then
editor:ToggleFold(ln)
end
end
end
editor:EnsureCaretVisible()
end
function EnsureRangeVisible(posStart, posEnd)
local editor = GetEditor()
if posStart > posEnd then
posStart, posEnd = posEnd, posStart
end
local lineStart = editor:LineFromPosition(posStart)
local lineEnd = editor:LineFromPosition(posEnd)
for line = lineStart, lineEnd do
editor:EnsureVisibleEnforcePolicy(line)
end
end
function SetAllEditorsReadOnly(enable)
for id, document in pairs(openDocuments) do
local editor = document.editor
editor:SetReadOnly(enable)
end
end
-----------------
-- Debug related
function ClearAllCurrentLineMarkers()
for id, document in pairs(openDocuments) do
local editor = document.editor
editor:MarkerDeleteAll(CURRENT_LINE_MARKER)
end
end
function CompileProgram(editor)
local editorText = editor:GetText()
local id = editor:GetId()
local filePath = DebuggerMakeFileName(editor, openDocuments[id].filePath)
local ret, errMsg, line_num = wxlua.CompileLuaScript(editorText, filePath)
if ide.frame.menuBar:IsChecked(ID_CLEAROUTPUT) then
ClearOutput()
end
if line_num > -1 then
DisplayOutput("Compilation error on line number :"..tostring(line_num).."\n"..errMsg.."\n")
editor:GotoLine(line_num-1)
else
DisplayOutput("Compilation successful.\n")
end
return line_num == -1 -- return true if it compiled ok
end
------------------
-- Save & Close
function SaveIfModified(editor)
local id = editor:GetId()
if openDocuments[id].isModified then
local saved = false
if not openDocuments[id].filePath then
local ret = wx.wxMessageBox("You must save the program before running it.\nPress cancel to abort running.",
"Save file?", wx.wxOK + wx.wxCANCEL + wx.wxCENTRE, ide.frame)
if ret == wx.wxOK then
saved = SaveFileAs(editor)
end
else
saved = SaveFile(editor, openDocuments[id].filePath)
end
if saved then
openDocuments[id].isModified = false
else
return false -- not saved
end
end
return true -- saved
end
function GetOpenFiles()
local opendocs = {}
for id, document in pairs(ide.openDocuments) do
if (document.filePath) then
local wxfname = wx.wxFileName(document.filePath)
wxfname:Normalize()
table.insert(opendocs,{fname=wxfname:GetFullPath(),id=document.index,
cursorpos = document.editor:GetCurrentPos()})
end
end
-- to keep tab order
table.sort(opendocs,function(a,b) return (a.id < b.id) end)
local openfiles = {}
for i,doc in ipairs(opendocs) do
table.insert(openfiles,{filename = doc.fname, cursorpos = doc.cursorpos} )
end
local id = GetEditor()
id = id and id:GetId()
return openfiles, id and openDocuments[id].index or 0
end
function SetOpenFiles(nametab,index)
for i,doc in ipairs(nametab) do
local editor = LoadFile(doc.filename,nil,true)
if editor then
editor:SetCurrentPos(doc.cursorpos or 0)
editor:SetSelectionStart(doc.cursorpos or 0)
editor:SetSelectionEnd(doc.cursorpos or 0)
editor:EnsureCaretVisible()
end
end
notebook:SetSelection(index or 0)
end
local beforeFullScreenPerspective
function ShowFullScreen(setFullScreen)
if setFullScreen then
beforeFullScreenPerspective = uimgr:SavePerspective()
uimgr:GetPane("bottomnotebook"):Show(false)
uimgr:GetPane("projpanel"):Show(false)
elseif beforeFullScreenPerspective then
uimgr:LoadPerspective(beforeFullScreenPerspective)
beforeFullScreenPerspective = nil
end
uimgr:GetPane("toolBar"):Show(not setFullScreen)
uimgr:Update()
frame:ShowFullScreen(setFullScreen)
end
function CloseWindow(event)
exitingProgram = true -- don't handle focus events
if not SaveOnExit(event:CanVeto()) then
event:Veto()
exitingProgram = false
return
end
ShowFullScreen(false)
SettingsSaveProjectSession(FileTreeGetProjects())
SettingsSaveFileSession(GetOpenFiles())
SettingsSaveView()
SettingsSaveFramePosition(ide.frame, "MainFrame")
SettingsSaveEditorSettings()
DebuggerCloseWatchWindow()
DebuggerKillClient()
ide.settings:delete() -- always delete the config
event:Skip()
end
frame:Connect(wx.wxEVT_CLOSE_WINDOW, CloseWindow)

View File

@@ -1,309 +1,467 @@
-- Integration with MobDebug
-- Copyright Paul Kulchenko 2011
local copas = require "copas"
local socket = require "socket"
local mobdebug = require "mobdebug"
local debugger = {}
debugger.server = nil -- DebuggerServer object when debugging, else nil
debugger.running = false -- true when the debuggee is running
debugger.portnumber = 8171 -- the port # to use for debugging
debugger.watchWindow = nil -- the watchWindow, nil when not created
debugger.watchListCtrl = nil -- the child listctrl in the watchWindow
ide.debugger = debugger
local notebook = ide.frame.vsplitter.splitter.notebook
debugger.shell = function(expression)
if debugger.server and not debugger.running then
copas.addthread(function ()
local value, _, err = debugger.handle('eval ' .. expression)
if err ~= nil then value, _, err = debugger.handle('exec ' .. expression) end
if err then DisplayShellErr(err)
else DisplayShell(value)
end
end)
end
end
debugger.listen = function()
local server = socket.bind("*", debugger.portnumber)
DisplayOutput("Started debugger server; clients can connect to "..wx.wxGetHostName()..":"..debugger.portnumber..".\n")
copas.autoclose = false
copas.addserver(server, function (skt)
debugger.server = copas.wrap(skt)
SetAllEditorsReadOnly(true)
local editor = GetEditor()
local filePath = ide.openDocuments[editor:GetId()].filePath;
debugger.basedir = string.gsub(wx.wxFileName(filePath):GetPath(wx.wxPATH_GET_VOLUME), "\\", "/")
-- load the remote file into the debugger
-- set basedir first, before loading to make sure that the path is correct
debugger.handle("basedir " .. debugger.basedir)
debugger.handle("load " .. filePath)
-- remove all breakpoints that may still be present from the last session
-- this only matters for those remote clients that reload scripts
-- without resetting their breakpoints
debugger.handle("delallb")
-- go over all windows and find all breakpoints
for id, document in pairs(ide.openDocuments) do
local editor = document.editor
local filePath = string.gsub(document.filePath, "\\", "/")
line = editor:MarkerNext(0, BREAKPOINT_MARKER_VALUE)
while line ~= -1 do
debugger.handle("setb " .. filePath .. " " .. (line+1))
line = editor:MarkerNext(line + 1, BREAKPOINT_MARKER_VALUE)
end
end
local line = 1
editor:MarkerAdd(line-1, CURRENT_LINE_MARKER)
editor:EnsureVisibleEnforcePolicy(line-1)
ShellSupportRemote(debugger.shell, 0)
DisplayOutput("Started remote debugging session (base directory: " .. debugger.basedir .. "/).\n")
end)
end
debugger.handle = function(line)
local _G = _G
local os = os
os.exit = function () end
_G.print = function () end
debugger.running = true
local file, line, err = mobdebug.handle(line, debugger.server)
debugger.running = false
return file, line, err
end
debugger.run = function(command)
if debugger.server and not debugger.running then
copas.addthread(function ()
while true do
local file, line, err = debugger.handle(command)
if line == nil then
debugger.server = nil
SetAllEditorsReadOnly(false)
ShellSupportRemote(nil, 0)
if err then DisplayOutput(err .. "\n") end
DisplayOutput("Completed debugging session.\n")
return
else
if debugger.basedir and not wx.wxIsAbsolutePath(file) then
file = debugger.basedir .. "/" .. file
end
if ActivateDocument(file, line) then
debugger.updateWatches()
return
else
command = "out" -- redo now trying to get out of this file
end
end
end
end)
end
end
debugger.updateBreakpoint = function(command)
if debugger.server and not debugger.running then
copas.addthread(function ()
debugger.handle(command)
end)
end
end
debugger.updateWatches = function()
local watchListCtrl = debugger.watchListCtrl
if watchListCtrl and debugger.server and not debugger.running then
copas.addthread(function ()
for idx = 0, watchListCtrl:GetItemCount() - 1 do
local expression = watchListCtrl:GetItemText(idx)
local value = debugger.handle('eval ' .. expression)
watchListCtrl:SetItem(idx, 1, value)
end
end)
end
end
debugger.update = function() copas.step(0) end
debugger.listen()
function CloseWatchWindow()
if (debugger.watchWindow) then
SettingsSaveFramePosition(debugger.watchWindow, "WatchWindow")
debugger.watchListCtrl = nil
debugger.watchWindow = nil
end
end
function CreateWatchWindow()
local width = 200
local watchWindow = wx.wxFrame(ide.frame, wx.wxID_ANY,
"Watch Window",
wx.wxDefaultPosition, wx.wxSize(width, 160),
wx.wxDEFAULT_FRAME_STYLE + wx.wxFRAME_FLOAT_ON_PARENT)
debugger.watchWindow = watchWindow
local watchMenu = wx.wxMenu{
{ ID_ADDWATCH, "&Add Watch" },
{ ID_EDITWATCH, "&Edit Watch\tF2" },
{ ID_REMOVEWATCH, "&Remove Watch" },
{ ID_EVALUATEWATCH, "Evaluate &Watches" }}
local watchMenuBar = wx.wxMenuBar()
watchMenuBar:Append(watchMenu, "&Watches")
watchWindow:SetMenuBar(watchMenuBar)
local watchListCtrl = wx.wxListCtrl(watchWindow, ID_WATCH_LISTCTRL,
wx.wxDefaultPosition, wx.wxDefaultSize,
wx.wxLC_REPORT + wx.wxLC_EDIT_LABELS)
debugger.watchListCtrl = watchListCtrl
local info = wx.wxListItem()
info:SetMask(wx.wxLIST_MASK_TEXT + wx.wxLIST_MASK_WIDTH)
info:SetText("Expression")
info:SetWidth(width * 0.45)
watchListCtrl:InsertColumn(0, info)
info:SetText("Value")
info:SetWidth(width * 0.45)
watchListCtrl:InsertColumn(1, info)
watchWindow:CentreOnParent()
SettingsRestoreFramePosition(watchWindow, "WatchWindow")
watchWindow:Show(true)
local function FindSelectedWatchItem()
local count = watchListCtrl:GetSelectedItemCount()
if count > 0 then
for idx = 0, watchListCtrl:GetItemCount() - 1 do
if watchListCtrl:GetItemState(idx, wx.wxLIST_STATE_FOCUSED) ~= 0 then
return idx
end
end
end
return -1
end
watchWindow:Connect( wx.wxEVT_CLOSE_WINDOW,
function (event)
CloseWatchWindow()
watchWindow = nil
watchListCtrl = nil
event:Skip()
end)
watchWindow:Connect(ID_ADDWATCH, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
local row = watchListCtrl:InsertItem(watchListCtrl:GetItemCount(), "Expr")
watchListCtrl:SetItem(row, 0, "Expr")
watchListCtrl:SetItem(row, 1, "Value")
watchListCtrl:EditLabel(row)
end)
watchWindow:Connect(ID_EDITWATCH, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
local row = FindSelectedWatchItem()
if row >= 0 then
watchListCtrl:EditLabel(row)
end
end)
watchWindow:Connect(ID_EDITWATCH, wx.wxEVT_UPDATE_UI,
function (event)
event:Enable(watchListCtrl:GetSelectedItemCount() > 0)
end)
watchWindow:Connect(ID_REMOVEWATCH, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
local row = FindSelectedWatchItem()
if row >= 0 then
watchListCtrl:DeleteItem(row)
end
end)
watchWindow:Connect(ID_REMOVEWATCH, wx.wxEVT_UPDATE_UI,
function (event)
event:Enable(watchListCtrl:GetSelectedItemCount() > 0)
end)
watchWindow:Connect(ID_EVALUATEWATCH, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
debugger.updateWatches()
end)
watchWindow:Connect(ID_EVALUATEWATCH, wx.wxEVT_UPDATE_UI,
function (event)
event:Enable(watchListCtrl:GetItemCount() > 0)
end)
watchListCtrl:Connect(wx.wxEVT_COMMAND_LIST_END_LABEL_EDIT,
function (event)
watchListCtrl:SetItem(event:GetIndex(), 0, event:GetText())
debugger.updateWatches()
event:Skip()
end)
end
function MakeDebugFileName(editor, filePath)
if not filePath then
filePath = "file"..tostring(editor)
end
return filePath
end
function ToggleDebugMarker(editor, line)
local markers = editor:MarkerGet(line)
if markers >= CURRENT_LINE_MARKER_VALUE then
markers = markers - CURRENT_LINE_MARKER_VALUE
end
local id = editor:GetId()
local filePath = MakeDebugFileName(editor, ide.openDocuments[id].filePath)
if markers >= BREAKPOINT_MARKER_VALUE then
editor:MarkerDelete(line, BREAKPOINT_MARKER)
if debugger.server then
debugger.updateBreakpoint("delb " .. filePath .. " " .. (line+1))
end
else
editor:MarkerAdd(line, BREAKPOINT_MARKER)
if debugger.server then
debugger.updateBreakpoint("setb " .. filePath .. " " .. (line+1))
end
end
end
function ActivateDocument(fileName, line)
if not wx.wxIsAbsolutePath(fileName) then
fileName = wx.wxGetCwd().."/"..fileName
end
if wx.__WXMSW__ then
fileName = wx.wxUnix2DosFilename(fileName)
end
local fileFound = false
for id, document in pairs(ide.openDocuments) do
local editor = document.editor
-- for running in cygwin, use same type of separators
filePath = string.gsub(document.filePath, "\\", "/")
local fileName = string.gsub(fileName, "\\", "/")
if string.upper(filePath) == string.upper(fileName) then
local selection = document.index
notebook:SetSelection(selection)
SetEditorSelection(selection)
editor:MarkerAdd(line-1, CURRENT_LINE_MARKER)
editor:EnsureVisibleEnforcePolicy(line-1)
fileFound = true
break
end
end
return fileFound
end
-- Integration with MobDebug
-- Copyright Paul Kulchenko 2011
-- Original authors: Lomtik Software (J. Winwood & John Labenski)
-- Luxinia Dev (Eike Decker & Christoph Kubisch)
local copas = require "copas"
local socket = require "socket"
local mobdebug = require "mobdebug"
local ide = ide
local debugger = ide.debugger
debugger.server = nil -- DebuggerServer object when debugging, else nil
debugger.running = false -- true when the debuggee is running
debugger.listening = false -- true when the debugger is listening for a client
debugger.portnumber = 8171 -- the port # to use for debugging
debugger.watchWindow = nil -- the watchWindow, nil when not created
debugger.watchListCtrl = nil -- the child listctrl in the watchWindow
local notebook = ide.frame.notebook
local function updateWatchesSync()
local watchListCtrl = debugger.watchListCtrl
if watchListCtrl and debugger.server and not debugger.running then
for idx = 0, watchListCtrl:GetItemCount() - 1 do
local expression = watchListCtrl:GetItemText(idx)
local value, _, error = debugger.evaluate(expression)
watchListCtrl:SetItem(idx, 1, value or ('error: ' .. error))
end
end
end
local function updateWatches()
if debugger.watchListCtrl and debugger.server and not debugger.running then
copas.addthread(updateWatchesSync)
end
end
local function activateDocument(fileName, line)
if (not fileName and line) then return end
if not wx.wxIsAbsolutePath(fileName) then
fileName = wx.wxGetCwd().."/"..fileName
end
if wx.__WXMSW__ then
fileName = wx.wxUnix2DosFilename(fileName)
end
local fileFound = false
for id, document in pairs(ide.openDocuments) do
local editor = document.editor
-- for running in cygwin, use same type of separators
filePath = string.gsub(document.filePath, "\\", "/")
local fileName = string.gsub(fileName, "\\", "/")
if string.upper(filePath) == string.upper(fileName) then
local selection = document.index
notebook:SetSelection(selection)
SetEditorSelection(selection)
ClearAllCurrentLineMarkers()
editor:MarkerAdd(line-1, CURRENT_LINE_MARKER)
editor:EnsureVisibleEnforcePolicy(line-1)
fileFound = true
break
end
end
return fileFound
end
debugger.shell = function(expression)
if debugger.server and not debugger.running then
copas.addthread(function ()
local addedret = false
local value, _, err = debugger.handle('exec ' .. expression)
if err and (err:find("'=' expected near '<eof>'") or
err:find("unexpected symbol near '")) then
value, _, err = debugger.handle('eval ' .. expression:gsub("^%s*=%s*",""))
addedret = true
end
if err then
if addedret then err = err:gsub('^%[string "return ', '[string "') end
DisplayShellErr(err)
elseif addedret or (value ~= nil and value ~= 'nil') then
DisplayShell(value)
end
end)
end
end
debugger.listen = function()
local server = socket.bind("*", debugger.portnumber)
DisplayOutput("Started debugger server; clients can connect to "..wx.wxGetHostName()..":"..debugger.portnumber..".\n")
copas.autoclose = false
copas.addserver(server, function (skt)
SetAllEditorsReadOnly(true)
local options = debugger.options or {}
local wxfilepath = GetEditorFileAndCurInfo()
local startfile = options.startfile or wxfilepath:GetFullPath()
local basedir = options.basedir
or FileTreeGetDir()
or wxfilepath:GetPath(wx.wxPATH_GET_VOLUME + wx.wxPATH_GET_SEPARATOR)
-- guarantee that the path has a trailing separator
debugger.basedir = wx.wxFileName.DirName(basedir):GetFullPath()
debugger.server = copas.wrap(skt)
debugger.socket = skt
debugger.loop = false
-- load the remote file into the debugger
-- set basedir first, before loading to make sure that the path is correct
debugger.handle("basedir " .. debugger.basedir)
-- remove all breakpoints that may still be present from the last session
-- this only matters for those remote clients that reload scripts
-- without resetting their breakpoints
debugger.handle("delallb")
-- go over all windows and find all breakpoints
for id, document in pairs(ide.openDocuments) do
local editor = document.editor
local filePath = document.filePath
line = editor:MarkerNext(0, BREAKPOINT_MARKER_VALUE)
while line ~= -1 do
debugger.handle("setb " .. filePath .. " " .. (line+1))
line = editor:MarkerNext(line + 1, BREAKPOINT_MARKER_VALUE)
end
end
if (options.run) then
local file, line = debugger.handle("run")
activateDocument(file, line)
else
local file, line = debugger.handle("load " .. startfile)
-- "load" can work in two ways: (1) it can load the requested file
-- OR (2) it can "refuse" to load it if the client was started
-- 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
-- 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)
end
end
end
if not activated then
DisplayOutput("Can't find file '" .. file .. "' to activate for debugging; open the file before debugging.\n")
return debugger.terminate()
end
else
activateDocument(startfile, 1)
end
end
if (not options.noshell) then
ShellSupportRemote(debugger.shell, debugger.pid)
end
DisplayOutput("Started remote debugging session (base directory: '" .. debugger.basedir .. "').\n")
end)
debugger.listening = true
end
debugger.handle = function(command, server)
local _G = _G
local os = os
os.exit = function () end
_G.print = function (...)
if (ide.config.debugger.verbose) then
DisplayOutput(...)
DisplayOutput("\n")
end
end
debugger.running = true
local file, line, err = mobdebug.handle(command, server and server or debugger.server)
debugger.running = false
return file, line, err
end
debugger.exec = function(command)
if debugger.server and not debugger.running then
copas.addthread(function ()
local out
while true do
local file, line, err = debugger.handle(out or command)
if out then out = nil end
if line == nil then
if err then DisplayOutput(err .. "\n") end
DebuggerStop()
return
else
if debugger.basedir and not wx.wxIsAbsolutePath(file) then
file = debugger.basedir .. file
end
if activateDocument(file, line) then
if debugger.loop then
updateWatchesSync()
else
updateWatches()
return
end
else
out = "out" -- redo now trying to get out of this file
end
end
end
end)
end
end
debugger.updateBreakpoint = function(command)
if debugger.server and not debugger.running then
copas.addthread(function ()
debugger.handle(command)
end)
end
end
debugger.update = function() copas.step(0) end
debugger.terminate = function()
if debugger.server then
if debugger.pid then -- if there is PID, try local kill
DebuggerKillClient()
else -- otherwise, trace graceful exit for the remote process
debugger.exec("exit")
copas.step(1) -- process 'exit' right away; doesn't guarantee the response
end
DebuggerStop()
end
end
debugger.step = function() debugger.exec("step") end
debugger.trace = function()
debugger.loop = true
debugger.exec("step")
end
debugger.over = function() debugger.exec("over") end
debugger.out = function() debugger.exec("out") end
debugger.run = function() debugger.exec("run") end
debugger.evaluate = function(expression) return debugger.handle('eval ' .. expression) end
debugger.breaknow = function()
-- stop if we're running a "trace" command
debugger.loop = false
-- force a step command; don't use copas interface as it checks
-- for the other side "reading" and the other side is not reading anything.
-- use the "original" socket to write a "step" command.
-- this will only break on the next Lua command.
if debugger.socket then
local running = debugger.running
-- this needs to be short as it will block the UI
debugger.socket:settimeout(0.25)
local file, line, err = debugger.handle("step", debugger.socket)
debugger.socket:settimeout(0)
-- restore running status
debugger.running = running
-- don't need to do anything else as the earlier call (run, step, etc.)
-- will get the results (file, line) back and will update the UI
end
end
debugger.breakpoint = function(file, line, state)
debugger.updateBreakpoint((state and "setb " or "delb ") .. file .. " " .. line)
end
----------------------------------------------
-- public api
function DebuggerAttachDefault(options)
debugger.options = options
if (debugger.listening) then return end
debugger.listen()
end
function DebuggerKillClient()
if (debugger.pid) then
-- using SIGTERM for some reason kills not only the debugee process,
-- but also some system processes, which leads to a blue screen crash
-- (at least on Windows Vista SP2)
local ret = wx.wxProcess.Kill(debugger.pid, wx.wxSIGKILL, wx.wxKILL_CHILDREN)
if ret == wx.wxKILL_OK then
DisplayOutput("Stopped process (pid: "..debugger.pid..").\n")
elseif ret ~= wx.wxKILL_NO_PROCESS then
DisplayOutput("Unable to stop process (pid: "..debugger.pid.."), code "..tostring(ret)..".\n")
end
debugger.pid = nil
end
end
function DebuggerStop()
if (debugger.server) then
debugger.server = nil
debugger.pid = nil
SetAllEditorsReadOnly(false)
ShellSupportRemote(nil, 0)
ClearAllCurrentLineMarkers()
DisplayOutput("Completed debugging session.\n")
end
end
function DebuggerCreateStackWindow()
DisplayOutput("Not Yet Implemented\n")
end
function DebuggerCloseStackWindow()
end
function DebuggerCloseWatchWindow()
if (debugger.watchWindow) then
SettingsSaveFramePosition(debugger.watchWindow, "WatchWindow")
debugger.watchListCtrl = nil
debugger.watchWindow = nil
end
end
function DebuggerCreateWatchWindow()
local width = 200
local watchWindow = wx.wxFrame(ide.frame, wx.wxID_ANY,
"Watch Window",
wx.wxDefaultPosition, wx.wxSize(width, 160),
wx.wxDEFAULT_FRAME_STYLE + wx.wxFRAME_FLOAT_ON_PARENT)
debugger.watchWindow = watchWindow
local watchMenu = wx.wxMenu{
{ ID_ADDWATCH, "&Add Watch" },
{ ID_EDITWATCH, "&Edit Watch\tF2" },
{ ID_REMOVEWATCH, "&Remove Watch" },
{ ID_EVALUATEWATCH, "Evaluate &Watches" }}
local watchMenuBar = wx.wxMenuBar()
watchMenuBar:Append(watchMenu, "&Watches")
watchWindow:SetMenuBar(watchMenuBar)
local watchListCtrl = wx.wxListCtrl(watchWindow, ID_WATCH_LISTCTRL,
wx.wxDefaultPosition, wx.wxDefaultSize,
wx.wxLC_REPORT + wx.wxLC_EDIT_LABELS)
debugger.watchListCtrl = watchListCtrl
local info = wx.wxListItem()
info:SetMask(wx.wxLIST_MASK_TEXT + wx.wxLIST_MASK_WIDTH)
info:SetText("Expression")
info:SetWidth(width * 0.45)
watchListCtrl:InsertColumn(0, info)
info:SetText("Value")
info:SetWidth(width * 0.45)
watchListCtrl:InsertColumn(1, info)
watchWindow:CentreOnParent()
SettingsRestoreFramePosition(watchWindow, "WatchWindow")
watchWindow:Show(true)
local function findSelectedWatchItem()
local count = watchListCtrl:GetSelectedItemCount()
if count > 0 then
for idx = 0, watchListCtrl:GetItemCount() - 1 do
if watchListCtrl:GetItemState(idx, wx.wxLIST_STATE_FOCUSED) ~= 0 then
return idx
end
end
end
return -1
end
watchWindow:Connect(wx.wxEVT_CLOSE_WINDOW,
function (event)
DebuggerCloseWatchWindow()
watchWindow = nil
watchListCtrl = nil
event:Skip()
end)
watchWindow:Connect(ID_ADDWATCH, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
local row = watchListCtrl:InsertItem(watchListCtrl:GetItemCount(), "Expr")
watchListCtrl:SetItem(row, 0, "Expr")
watchListCtrl:SetItem(row, 1, "Value")
watchListCtrl:EditLabel(row)
end)
watchWindow:Connect(ID_EDITWATCH, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
local row = findSelectedWatchItem()
if row >= 0 then
watchListCtrl:EditLabel(row)
end
end)
watchWindow:Connect(ID_EDITWATCH, wx.wxEVT_UPDATE_UI,
function (event)
event:Enable(watchListCtrl:GetSelectedItemCount() > 0)
end)
watchWindow:Connect(ID_REMOVEWATCH, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
local row = findSelectedWatchItem()
if row >= 0 then
watchListCtrl:DeleteItem(row)
end
end)
watchWindow:Connect(ID_REMOVEWATCH, wx.wxEVT_UPDATE_UI,
function (event)
event:Enable(watchListCtrl:GetSelectedItemCount() > 0)
end)
watchWindow:Connect(ID_EVALUATEWATCH, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
updateWatches()
end)
watchWindow:Connect(ID_EVALUATEWATCH, wx.wxEVT_UPDATE_UI,
function (event)
event:Enable(watchListCtrl:GetItemCount() > 0)
end)
watchListCtrl:Connect(wx.wxEVT_COMMAND_LIST_END_LABEL_EDIT,
function (event)
watchListCtrl:SetItem(event:GetIndex(), 0, event:GetText())
updateWatches()
event:Skip()
end)
end
function DebuggerMakeFileName(editor, filePath)
if not filePath then
filePath = "file"..tostring(editor)
end
return filePath
end
function DebuggerToggleBreakpoint(editor, line)
local markers = editor:MarkerGet(line)
if markers >= CURRENT_LINE_MARKER_VALUE then
markers = markers - CURRENT_LINE_MARKER_VALUE
end
local id = editor:GetId()
local filePath = DebuggerMakeFileName(editor, ide.openDocuments[id].filePath)
if markers >= BREAKPOINT_MARKER_VALUE then
editor:MarkerDelete(line, BREAKPOINT_MARKER)
if debugger.server then
debugger.breakpoint(filePath, line+1, false)
end
else
editor:MarkerAdd(line, BREAKPOINT_MARKER)
if debugger.server then
debugger.breakpoint(filePath, line+1, true)
end
end
end

File diff suppressed because it is too large Load Diff

View File

@@ -1,254 +1,345 @@
-- authors: Luxinia Dev (Eike Decker & Christoph Kubisch)
---------------------------------------------------------
local ide = ide
--
-- filetree, treectrl for drive & project
--
ide.filetree = {
dirdriveText = "",
dirdriveTextArray = {},
projdirText = "",
projdirTextArray = {},
showroot = true,
dirdata = {
root_id = nil,
rootdir = "",
},
projdata = {
root_id = nil,
rootdir = "",
},
imglist,
newfiledir,
}
local filetree = ide.filetree
local frame = ide.frame
local sidenotebook = ide.frame.vsplitter.sidenotebook
-- generic tree
-- ------------
do
filetree.imglist = wx.wxImageList(16,16)
-- 0 = directory
filetree.imglist:Add(wx.wxArtProvider.GetIcon(wx.wxART_FOLDER,wx.wxART_TOOLBAR, wx.wxSize(16, 16)))
-- 1 = file known spec
filetree.imglist:Add(wx.wxArtProvider.GetIcon(wx.wxART_HELP_PAGE ,wx.wxART_TOOLBAR, wx.wxSize(16, 16)))
-- 2 = file rest
filetree.imglist:Add(wx.wxArtProvider.GetIcon(wx.wxART_NORMAL_FILE,wx.wxART_TOOLBAR, wx.wxSize(16, 16)))
end
local function treeAddDir(tree,parent_id,rootdir)
tree:DeleteChildren(parent_id)
local search = rootdir..string_Pathsep.."*.*"
local dirs = FileSysGet(search,wx.wxDIR)
-- append directories
for i,dir in ipairs(dirs) do
local dir_id = tree:AppendItem(parent_id, dir:match("(%"..string_Pathsep..stringset_File.."+)$"),0)
tree:SetItemHasChildren(dir_id,FileSysHasContent(dir))
end
-- then append files
local files = FileSysGet(search,wx.wxFILE)
for i,file in ipairs(files) do
local fname = file:match("%"..string_Pathsep.."("..stringset_File.."+)$")
local known = GetSpec(GetFileExt(fname))
tree:AppendItem(parent_id, fname,known and 1 or 2)
end
end
local function treeGetItemFullName(tree,treedata,item_id,isfile)
local str = isfile and string_Pathsep or ""
str = str..tree:GetItemText(item_id)
local cur = str
local stop = 4
while (#cur > 0) do
item_id = tree:GetItemParent(item_id)
cur = tree:GetItemText(item_id)
str = cur..str
end
return ((not filetree.showroot) and filetree.projdata.rootdir or "").. str
end
local function treeSetRoot(tree,treedata,rootdir)
tree:DeleteAllItems()
if (not wx.wxDirExists(rootdir)) then
treedata.root_id = nil
tree:AddRoot("Invalid")
return
end
local root_id = tree:AddRoot(rootdir,0)
treedata.root_id = root_id
treedata.rootdir = rootdir
treeAddDir(tree,root_id,rootdir)
filetree.newfiledir = rootdir..string_Pathsep
tree:Expand(root_id)
end
local function treeSetConnectorsAndIcons(tree,treedata)
tree:SetImageList(filetree.imglist)
-- connect to some events from the wxTreeCtrl
tree:Connect( wx.wxEVT_COMMAND_TREE_ITEM_EXPANDING,
function( event )
local item_id = event:GetItem()
local dir = treeGetItemFullName(tree,treedata,item_id)
DisplayOutput(dir.."\n")
treeAddDir(tree,item_id,dir)
return true
end )
tree:Connect( wx.wxEVT_COMMAND_TREE_ITEM_COLLAPSED,
function( event )
local item_id = event:GetItem()
tree:DeleteChildren(item_id)
-- directories must stay expandable if they have content
local dir = treeGetItemFullName(tree,treedata,item_id)
tree:SetItemHasChildren(item_id,FileSysHasContent(dir))
return true
end )
tree:Connect( wx.wxEVT_COMMAND_TREE_ITEM_ACTIVATED,
function( event )
local item_id = event:GetItem()
if (tree:GetItemImage(item_id) == 0) then return end
-- openfile
local name = treeGetItemFullName(tree,treedata,item_id,true)
LoadFile(name,nil,true)
end )
tree:Connect( wx.wxEVT_COMMAND_TREE_SEL_CHANGED,
function( event )
local item_id = event:GetItem()
-- set "newfile-path"
local isfile = tree:GetItemImage(item_id) ~= 0
filetree.newfiledir = treeGetItemFullName(tree,treedata,item_id,isfile)
if (isfile) then
-- remove file
filetree.newfiledir = wx.wxFileName(filetree.newfiledir):GetPath(wx.wxPATH_GET_VOLUME)
end
filetree.newfiledir = filetree.newfiledir..string_Pathsep
end )
end
-- project
-- panel
-- ( combobox, button)
-- ( treectrl)
local projpanel = wx.wxPanel(sidenotebook,wx.wxID_ANY)
local projcombobox = wx.wxComboBox(projpanel, ID "filetree.proj.drivecb",
filetree.projdirText,
wx.wxDefaultPosition, wx.wxDefaultSize,
filetree.projdirTextArray, wx.wxTE_PROCESS_ENTER)
local projbutton = wx.wxButton(projpanel, ID "debug.projectdir.choose", "...",wx.wxDefaultPosition, wx.wxSize(26,20))
local projtree = wx.wxTreeCtrl(projpanel, ID "filetree.projtree",
wx.wxDefaultPosition, wx.wxDefaultSize,
filetree.showroot
and (wx.wxTR_LINES_AT_ROOT + wx.wxTR_HAS_BUTTONS + wx.wxTR_SINGLE)
or (wx.wxTR_HAS_BUTTONS + wx.wxTR_SINGLE + wx.wxTR_HIDE_ROOT))
local projTopSizer = wx.wxBoxSizer( wx.wxHORIZONTAL );
projTopSizer:Add(projcombobox, 1, wx.wxALL + wx.wxALIGN_LEFT + wx.wxGROW, 0)
projTopSizer:Add(projbutton, 0, wx.wxALL + wx.wxALIGN_RIGHT + wx.wxADJUST_MINSIZE, 0)
local projSizer = wx.wxBoxSizer( wx.wxVERTICAL );
projSizer:Add(projTopSizer, 0, wx.wxALL + wx.wxALIGN_CENTER_HORIZONTAL + wx.wxGROW, 0)
projSizer:Add(projtree, 1, wx.wxALL + wx.wxALIGN_LEFT + wx.wxGROW, 0)
projpanel:SetSizer(projSizer)
-- proj connectors
-- ---------------
local function projcomboboxUpdate(event)
local cur = projcombobox:GetValue()
local fn = wx.wxFileName(cur)
fn:Normalize()
filetree:UpdateProjectDir(fn:GetFullPath(), event:GetEventType() == wx.wxEVT_COMMAND_COMBOBOX_SELECTED)
end
projpanel:Connect(ID "filetree.proj.drivecb", wx.wxEVT_COMMAND_COMBOBOX_SELECTED, projcomboboxUpdate)
projpanel:Connect(ID "filetree.proj.drivecb", wx.wxEVT_COMMAND_TEXT_ENTER, projcomboboxUpdate)
treeSetConnectorsAndIcons(projtree,filetree.projdata)
-- proj functions
-- ---------------
function filetree:UpdateProjectDir(newdir, cboxsel)
if (newdir and newdir:sub(-3,-2) == string_Pathsep) then
newdir = newdir:sub(0,-2)
end
if ((not newdir) or filetree.projdirText == newdir or not wx.wxDirExists(newdir)) then return end
filetree.projdirText = newdir
--if (not cboxsel) then
PrependStringToArray(filetree.projdirTextArray,newdir,ide.config.projecthistorylength)
projcombobox:Clear()
projcombobox:Append(filetree.projdirTextArray)
if (not cboxsel) then
projcombobox:SetValue(newdir)
--projcombobox:SetValue(newdir)
else
projcombobox:Select(0)
end
--end
UpdateProjectDir(newdir,true)
treeSetRoot(projtree,filetree.projdata,newdir)
end
projpanel.projbutton = projbutton
projpanel.projcombobox = projcombobox
projpanel.projtree = projtree
sidenotebook.projpanel = projpanel
sidenotebook:AddPage(projpanel, "Project",true)
function GetFileTreeDir()
-- atm only projtree
--print(ide.frame.vsplitter:IsSplit(),filetree.newfiledir)
return ide.frame.vsplitter:IsSplit() and filetree.newfiledir
end
function SetProjects(tab)
filetree.projdirTextArray = tab
if (tab and tab[1]) then
filetree:UpdateProjectDir(tab[1])
end
end
function GetProjects()
return filetree.projdirTextArray
end
-- authors: Luxinia Dev (Eike Decker & Christoph Kubisch)
---------------------------------------------------------
local ide = ide
--
-- filetree, treectrl for drive & project
--
ide.filetree = {
dirdriveText = "",
dirdriveTextArray = {},
projdirText = "",
projdirTextArray = {},
showroot = true,
dirdata = {
root_id = nil,
rootdir = "",
},
projdata = {
root_id = nil,
rootdir = "",
},
imglist,
newfiledir,
}
local filetree = ide.filetree
local frame = ide.frame
-- generic tree
-- ------------
do
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))
-- 1 = file known spec
filetree.imglist:Add(wx.wxArtProvider.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))
end
local function treeAddDir(tree,parent_id,rootdir)
local item, cookie = tree:GetFirstChild(parent_id)
local items = {}
while true do
if not item:IsOk() then break end
items[tree:GetItemText(item) .. tree:GetItemImage(item)] = item
item, cookie = tree:GetNextChild(item, cookie)
end
local curr
local search = rootdir..string_Pathsep.."*.*"
local dirs = FileSysGet(search,wx.wxDIR)
-- append directories
for i,dir in ipairs(dirs) do
local name = dir:match("%"..string_Pathsep.."("..stringset_File.."+)$")
local icon = 0
local item = items[name .. icon]
if item then -- existing item
-- keep deleting items until we find item
while true do
local next = curr and tree:GetNextSibling(curr)
or tree:GetFirstChild(parent_id)
if not next:IsOk() or name == tree:GetItemText(next) then
curr = next
break
end
tree:Delete(next)
end
else -- new item
local dir_id = curr and tree:InsertItem(parent_id, curr, name, icon)
or tree:PrependItem(parent_id, name, icon)
tree:SetItemHasChildren(dir_id,FileSysHasContent(dir))
curr = dir_id
end
end
-- then append files
local files = FileSysGet(search,wx.wxFILE)
for i,file in ipairs(files) do
local name = file:match("%"..string_Pathsep.."("..stringset_File.."+)$")
local known = GetSpec(GetFileExt(fname))
local icon = known and 1 or 2
local item = items[name .. icon]
if item then -- existing item
-- keep deleting items until we find item
while true do
local next = curr and tree:GetNextSibling(curr)
or tree:GetFirstChild(parent_id)
if not next:IsOk() or name == tree:GetItemText(next) then
curr = next
break
end
tree:Delete(next)
end
else -- new item
curr = curr and tree:InsertItem(parent_id, curr, name, icon)
or tree:PrependItem(parent_id, name, icon)
end
end
-- delete any leftovers (something that exists in the tree, but not on disk)
while true do
local next = curr and tree:GetNextSibling(curr)
or tree:GetFirstChild(parent_id)
if not next:IsOk() then break end
tree:Delete(next)
end
tree:SetItemHasChildren(parent_id,
tree:GetChildrenCount(parent_id, false) > 0)
end
local function treeGetItemFullName(tree,treedata,item_id)
local str = tree:GetItemText(item_id)
local cur = str
while (#cur > 0) do
item_id = tree:GetItemParent(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
end
local function treeSetRoot(tree,treedata,rootdir)
tree:DeleteAllItems()
if (not wx.wxDirExists(rootdir)) then
treedata.root_id = nil
tree:AddRoot("Invalid")
return
end
local root_id = tree:AddRoot(rootdir,0)
treedata.root_id = root_id
treedata.rootdir = rootdir
treeAddDir(tree,root_id,rootdir)
filetree.newfiledir = rootdir
tree:Expand(root_id)
end
local function treeSetConnectorsAndIcons(tree,treedata)
tree:SetImageList(filetree.imglist)
-- connect to some events from the wxTreeCtrl
tree:Connect( wx.wxEVT_COMMAND_TREE_ITEM_EXPANDING,
function( event )
local item_id = event:GetItem()
local dir = treeGetItemFullName(tree,treedata,item_id)
treeAddDir(tree,item_id,dir)
return true
end )
tree:Connect( wx.wxEVT_COMMAND_TREE_ITEM_COLLAPSED,
function( event )
-- don't need to do anything here
return true
end )
tree:Connect( wx.wxEVT_COMMAND_TREE_ITEM_ACTIVATED,
function( event )
local item_id = event:GetItem()
local name = treeGetItemFullName(tree,treedata,item_id)
-- refresh the folder
if (tree:GetItemImage(item_id) == 0) then
if wx.wxFileName(name):DirExists() then
treeAddDir(tree,item_id,name) -- refresh the content
else -- stale filetree information; rescan
treeAddDir(tree,tree:GetItemParent(item_id),name)
end
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
end
end )
tree:Connect( wx.wxEVT_COMMAND_TREE_SEL_CHANGED,
function( event )
local item_id = event:GetItem()
-- set "newfile-path"
local isfile = tree:GetItemImage(item_id) ~= 0
filetree.newfiledir = treeGetItemFullName(tree,treedata,item_id)
if (isfile) then
-- remove file
filetree.newfiledir = wx.wxFileName(filetree.newfiledir):GetPath(wx.wxPATH_GET_VOLUME)
end
filetree.newfiledir = filetree.newfiledir..string_Pathsep
end )
end
-- project
-- panel
-- (combobox, button)
-- (treectrl)
local projpanel = ide.frame.projpanel
local projcombobox = wx.wxComboBox(projpanel, ID "filetree.proj.drivecb",
filetree.projdirText,
wx.wxDefaultPosition, wx.wxDefaultSize,
filetree.projdirTextArray, wx.wxTE_PROCESS_ENTER)
local projbutton = wx.wxButton(projpanel, ID "debug.projectdir.choose", "...",wx.wxDefaultPosition, wx.wxSize(26,20))
local projtree = wx.wxTreeCtrl(projpanel, ID "filetree.projtree",
wx.wxDefaultPosition, wx.wxDefaultSize,
filetree.showroot
and (wx.wxTR_LINES_AT_ROOT + wx.wxTR_HAS_BUTTONS + wx.wxTR_SINGLE)
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())
local projTopSizer = wx.wxBoxSizer( wx.wxHORIZONTAL );
projTopSizer:Add(projcombobox, 1, wx.wxALL + wx.wxALIGN_LEFT + wx.wxGROW, 0)
projTopSizer:Add(projbutton, 0, wx.wxALL + wx.wxALIGN_RIGHT + wx.wxADJUST_MINSIZE + wx.wxALIGN_CENTER_VERTICAL, 0)
local projSizer = wx.wxBoxSizer( wx.wxVERTICAL );
projSizer:Add(projTopSizer, 0, wx.wxALL + wx.wxALIGN_CENTER_HORIZONTAL + wx.wxGROW, 0)
projSizer:Add(projtree, 1, wx.wxALL + wx.wxALIGN_LEFT + wx.wxGROW, 0)
projpanel:SetSizer(projSizer)
-- proj connectors
-- ---------------
local function projcomboboxUpdate(event)
local cur = projcombobox:GetValue()
local fn = wx.wxFileName(cur)
fn:Normalize()
filetree:updateProjectDir(fn:GetFullPath(), event:GetEventType() == wx.wxEVT_COMMAND_COMBOBOX_SELECTED)
end
projpanel:Connect(ID "filetree.proj.drivecb", wx.wxEVT_COMMAND_COMBOBOX_SELECTED, projcomboboxUpdate)
projpanel:Connect(ID "filetree.proj.drivecb", wx.wxEVT_COMMAND_TEXT_ENTER, projcomboboxUpdate)
treeSetConnectorsAndIcons(projtree,filetree.projdata)
-- proj functions
-- ---------------
function filetree:updateProjectDir(newdir, cboxsel)
if (newdir and newdir:sub(-3,-2) == string_Pathsep) then
newdir = newdir:sub(0,-2)
end
if ((not newdir) or filetree.projdirText == newdir or not wx.wxDirExists(newdir)) then return end
filetree.projdirText = newdir
PrependStringToArray(filetree.projdirTextArray,newdir,ide.config.projecthistorylength)
projcombobox:Clear()
projcombobox:Append(filetree.projdirTextArray)
if (not cboxsel) then
projcombobox:SetValue(newdir)
else
projcombobox:Select(0)
end
ProjectUpdateProjectDir(newdir,true)
treeSetRoot(projtree,filetree.projdata,newdir)
-- sync with the current editor window and activate selected file
local editor = GetEditor()
if (editor) then
local id = GetEditor():GetId()
if ide.openDocuments[id] then
FileTreeMarkSelected(ide.openDocuments[id].filePath)
end
end
end
projpanel.projbutton = projbutton
projpanel.projcombobox = projcombobox
projpanel.projtree = projtree
function FileTreeGetDir()
return projpanel:IsShown() and filetree.newfiledir
and wx.wxFileName.DirName(filetree.newfiledir):GetFullPath()
end
function FileTreeSetProjects(tab)
filetree.projdirTextArray = tab
if (tab and tab[1]) then
filetree:updateProjectDir(tab[1])
end
end
function FileTreeGetProjects()
return filetree.projdirTextArray
end
local function findItem(tree, match)
local node = projtree:GetRootItem()
local label = tree:GetItemText(node)
local s, e = string.find(match, label)
if not s or s ~= 1 then return end
for token in string.gmatch(string.sub(match,e+1), "[^%"..string_Pathsep.."]+") do
local dir = treeGetItemFullName(tree,filetree.projdata,node)
treeAddDir(tree,node,dir)
local item, cookie = tree:GetFirstChild(node)
while true do
if not item:IsOk() then return end -- not found
if tree:GetItemText(item) == token then
node = item
break
end
item, cookie = tree:GetNextChild(item, cookie)
end
end
-- this loop exits only when a match is found
return node
end
local curr_id
function FileTreeMarkSelected(file)
if not file 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)
end
if item_id then
projtree:EnsureVisible(item_id)
projtree:SetItemBold(item_id, true)
curr_id = item_id
end
end
end

File diff suppressed because it is too large Load Diff

View File

@@ -1,213 +1,218 @@
-- authors: Luxinia Dev (Eike Decker & Christoph Kubisch)
-- Lomtik Software (J. Winwood & John Labenski)
---------------------------------------------------------
local ide = ide
-- Global variables
-- Markers for editor marker margin
BREAKPOINT_MARKER = 1
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")
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")
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 "")
fontItalic = wx.wxFont(ide.config.editor.fontsize or 10, wx.wxFONTFAMILY_MODERN, wx.wxFONTSTYLE_ITALIC, wx.wxFONTWEIGHT_NORMAL, false, ide.config.editor.fontname or "")
end
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")
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")
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 "")
ofontItalic = wx.wxFont(ide.config.outputshell.fontsize or 10, wx.wxFONTFAMILY_MODERN, wx.wxFONTSTYLE_ITALIC, wx.wxFONTWEIGHT_NORMAL, false, ide.config.outputshell.fontname or "")
end
ide.font = font
ide.fontItalic = fontItalic
ide.ofont = ofont
ide.ofontItalic = ofontItalic
-- wxWindow variables
local frame = nil -- wxFrame the main top level window
local toolBar = nil
local funclist = nil
local statusBar = nil
local menuBar = nil
local vsplitter = nil
local sidenotebook = nil
local splitter = nil -- wxSplitterWindow for the notebook and errorlog
local notebook = nil -- wxNotebook of editors
local bottomnotebook = nil -- notebook for the GUIs in the bottom line
local errorlog = nil -- wxStyledTextCtrl log window for messages
local shellbox = nil -- 2 wxStyledTextCtrl for lua shell
-- ----------------------------------------------------------------------------
-- Create the wxFrame
-- ----------------------------------------------------------------------------
frame = wx.wxFrame(wx.NULL, wx.wxID_ANY, GetIDEString("editor"))
menuBar = wx.wxMenuBar()
statusBar = frame:CreateStatusBar( 5 )
local status_txt_width = statusBar:GetTextExtent("OVRW")
statusBar:SetStatusWidths({-1, status_txt_width*6, status_txt_width, status_txt_width, status_txt_width*5})
statusBar:SetStatusText(GetIDEString("statuswelcome"))
frame:DragAcceptFiles(true)
frame:Connect(wx.wxEVT_DROP_FILES,function(evt)
local files = evt:GetFiles()
if not files or #files == 0 then return end
for i,f in ipairs(files) do
LoadFile(f,nil,true)
end
end)
toolBar = frame:CreateToolBar(wx.wxNO_BORDER + wx.wxTB_FLAT + wx.wxTB_DOCKABLE)
funclist = wx.wxChoice.new(toolBar,ID "toolBar.funclist",wx.wxDefaultPosition, wx.wxSize.new(300,16))
-- note: Ususally the bmp size isn't necessary, but the HELP icon is not the right size in MSW
local toolBmpSize = toolBar:GetToolBitmapSize()
toolBar:AddTool(ID_NEW, "New", wx.wxArtProvider.GetBitmap(wx.wxART_NORMAL_FILE, wx.wxART_MENU, toolBmpSize), "Create an empty document")
toolBar:AddTool(ID_OPEN, "Open", wx.wxArtProvider.GetBitmap(wx.wxART_FILE_OPEN, wx.wxART_MENU, toolBmpSize), "Open an existing document")
toolBar:AddTool(ID_SAVE, "Save", wx.wxArtProvider.GetBitmap(wx.wxART_FILE_SAVE, wx.wxART_MENU, toolBmpSize), "Save the current document")
toolBar:AddTool(ID_SAVEALL, "Save All", wx.wxArtProvider.GetBitmap(wx.wxART_NEW_DIR, wx.wxART_MENU, toolBmpSize), "Save all documents")
toolBar:AddSeparator()
toolBar:AddTool(ID_CUT, "Cut", wx.wxArtProvider.GetBitmap(wx.wxART_CUT, wx.wxART_MENU, toolBmpSize), "Cut the selection")
toolBar:AddTool(ID_COPY, "Copy", wx.wxArtProvider.GetBitmap(wx.wxART_COPY, wx.wxART_MENU, toolBmpSize), "Copy the selection")
toolBar:AddTool(ID_PASTE, "Paste", wx.wxArtProvider.GetBitmap(wx.wxART_PASTE, wx.wxART_MENU, toolBmpSize), "Paste text from the clipboard")
toolBar:AddSeparator()
toolBar:AddTool(ID_UNDO, "Undo", wx.wxArtProvider.GetBitmap(wx.wxART_UNDO, wx.wxART_MENU, toolBmpSize), "Undo last edit")
toolBar:AddTool(ID_REDO, "Redo", wx.wxArtProvider.GetBitmap(wx.wxART_REDO, wx.wxART_MENU, toolBmpSize), "Redo last undo")
toolBar:AddSeparator()
toolBar:AddTool(ID_FIND, "Find", wx.wxArtProvider.GetBitmap(wx.wxART_FIND, wx.wxART_MENU, toolBmpSize), "Find text")
toolBar:AddTool(ID_REPLACE, "Replace", wx.wxArtProvider.GetBitmap(wx.wxART_FIND_AND_REPLACE, wx.wxART_MENU, toolBmpSize), "Find and replace text")
toolBar:AddSeparator()
toolBar:AddTool(ID "debug.projectdir.fromfile", "Update", wx.wxArtProvider.GetBitmap(wx.wxART_GO_DIR_UP , wx.wxART_MENU, toolBmpSize), "Sets projectdir from file")
toolBar:AddSeparator()
toolBar:AddControl(funclist)
toolBar:Realize()
-- ----------------------------------------------------------------------------
-- Add the child windows to the frame
-- vertical splitter (splitter / sidenotebook)
vsplitter = wx.wxSplitterWindow(frame, wx.wxID_ANY,
wx.wxDefaultPosition, wx.wxDefaultSize,
wx.wxSP_3DSASH)
-- horizontal splitter (notebook,bottomnotebook)
splitter = wx.wxSplitterWindow(vsplitter, wx.wxID_ANY,
wx.wxDefaultPosition, wx.wxDefaultSize,
wx.wxSP_3DSASH)
local ph
splitter:Connect(wx.wxEVT_SIZE, function (evt)
local h = evt:GetSize():GetHeight()
ph = ph or h
local h2 = ph
ph = h
local dh = splitter:GetSashPosition()
splitter:SetSashPosition(dh-h2+h)
splitter:UpdateSize()
evt:Skip()
end)
-- notebook for editors
notebook = wx.wxNotebook(splitter, wx.wxID_ANY,
wx.wxDefaultPosition, wx.wxDefaultSize,
wx.wxCLIP_CHILDREN)
local current -- the currently active editor, needed by the focus selection
notebook:Connect(wx.wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED,
function (event)
current = event:GetSelection() -- update the active editor reference
SetEditorSelection(event:GetSelection())
event:Skip() -- skip to let page change
end)
notebook:Connect(wx.wxEVT_SET_FOCUS, -- Notepad tabs shouldn't be selectable,
function (event) -- select the editor then instead
SetEditorSelection(current) -- select the currently active one.
end)
-- bottomnotebook (errorlog,shellbox)
bottomnotebook = wx.wxNotebook(splitter, wx.wxID_ANY,
wx.wxDefaultPosition, wx.wxDefaultSize,
wx.wxCLIP_CHILDREN)
errorlog = wxstc.wxStyledTextCtrl(bottomnotebook, wx.wxID_ANY,wx.wxDefaultPosition, wx.wxDefaultSize,
wx.wxBORDER_STATIC)
bottomnotebook:AddPage(errorlog, "Output", true)
shellbox = wx.wxPanel(bottomnotebook,wx.wxID_ANY)
shellbox.output = wxstc.wxStyledTextCtrl(shellbox, ID "shellbox.output")
shellbox.input = wxstc.wxStyledTextCtrl(shellbox, ID "shellbox.input")
shellbox.run = wx.wxButton(shellbox, ID "shellbox.run", "Run")
shellbox.remote = wx.wxCheckBox(shellbox, ID "shellbox.remote", "Remote")
shellbox.remote:Disable()
local hsizer = wx.wxFlexGridSizer(0, 1, 0, 0)
hsizer:AddGrowableCol(0)
hsizer:AddGrowableRow(0)
hsizer:Add(shellbox.run, 0, wx.wxGROW+wx.wxALIGN_CENTER_VERTICAL, 0 )
hsizer:Add(shellbox.remote, 0, wx.wxGROW+wx.wxALIGN_CENTER_VERTICAL, 0 )
local vsizer = wx.wxFlexGridSizer(1, 0, 0, 0)
vsizer:AddGrowableCol(0)
vsizer:AddGrowableRow(0)
vsizer:Add(shellbox.input, 0, wx.wxGROW+wx.wxALIGN_CENTER_HORIZONTAL, 0 )
vsizer:Add(hsizer, 0, wx.wxGROW+wx.wxALIGN_CENTER_HORIZONTAL, 0 )
local gridsizer = wx.wxFlexGridSizer(0, 1, 0, 0)
gridsizer:AddGrowableCol(0)
gridsizer:AddGrowableRow(0)
gridsizer:Add(shellbox.output, 0, wx.wxGROW+wx.wxALIGN_CENTER_HORIZONTAL, 0 )
gridsizer:Add(vsizer, 0, wx.wxGROW+wx.wxALIGN_CENTER_HORIZONTAL, 0 )
shellbox:SetSizer(gridsizer)
bottomnotebook:AddPage(shellbox, "Lua shell",false)
-- sidenotebook
sidenotebook = wx.wxNotebook(vsplitter, wx.wxID_ANY,
wx.wxDefaultPosition, wx.wxDefaultSize,
wx.wxCLIP_CHILDREN)
-- init splitters
splitter:Initialize(notebook)
vsplitter:Initialize(splitter)
-------
-- hierarchy
bottomnotebook.shellbox = shellbox
bottomnotebook.errorlog = errorlog
splitter.bottomnotebook = bottomnotebook
splitter.notebook = notebook
vsplitter.splitter = splitter
vsplitter.sidenotebook = sidenotebook
toolBar.funclist = funclist
frame.vsplitter = vsplitter
frame.toolBar = toolBar
frame.statusBar = statusBar
frame.menuBar = menuBar
ide.frame = frame
-- authors: Luxinia Dev (Eike Decker & Christoph Kubisch)
-- Lomtik Software (J. Winwood & John Labenski)
---------------------------------------------------------
local ide = ide
-- Global variables
-- Markers for editor marker margin
BREAKPOINT_MARKER = 1
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")
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")
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 "")
fontItalic = wx.wxFont(ide.config.editor.fontsize or 10, wx.wxFONTFAMILY_MODERN, wx.wxFONTSTYLE_ITALIC, wx.wxFONTWEIGHT_NORMAL, false, ide.config.editor.fontname or "")
end
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")
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")
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 "")
ofontItalic = wx.wxFont(ide.config.outputshell.fontsize or 10, wx.wxFONTFAMILY_MODERN, wx.wxFONTSTYLE_ITALIC, wx.wxFONTWEIGHT_NORMAL, false, ide.config.outputshell.fontname or "")
end
ide.font = font
ide.fontItalic = fontItalic
ide.ofont = ofont
ide.ofontItalic = ofontItalic
-- ----------------------------------------------------------------------------
-- Create the wxFrame
-- ----------------------------------------------------------------------------
local function createFrame()
frame = wx.wxFrame(wx.NULL, wx.wxID_ANY, GetIDEString("editor"),
wx.wxDefaultPosition, wx.wxSize(1000, 700))
-- wrap into protected call as DragAcceptFiles fails on MacOS with
-- wxwidgets 2.8.12 even though it should work according to change notes
-- for 2.8.10: "Implemented wxWindow::DragAcceptFiles() on all platforms."
pcall(function() frame:DragAcceptFiles(true) end)
frame:Connect(wx.wxEVT_DROP_FILES,function(evt)
local files = evt:GetFiles()
if not files or #files == 0 then return end
for i,f in ipairs(files) do
LoadFile(f,nil,true)
end
end)
local menuBar = wx.wxMenuBar()
frame:SetMenuBar(menuBar)
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})
statusBar:SetStatusText(GetIDEString("statuswelcome"))
local mgr = wxaui.wxAuiManager()
frame.uimgr = mgr
mgr:SetManagedWindow(frame)
return frame
end
local function createToolBar(frame)
local toolBar = wx.wxToolBar(frame, wx.wxID_ANY,
wx.wxDefaultPosition, wx.wxDefaultSize, wx.wxTB_FLAT + wx.wxTB_NODIVIDER)
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 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: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: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: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: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:AddSeparator()
toolBar:AddControl(funclist)
toolBar:Realize()
toolBar.funclist = funclist
frame.toolBar = toolBar
return toolBar
end
local function createNotebook(frame)
-- notebook for editors
local notebook = wxaui.wxAuiNotebook(frame, wx.wxID_ANY,
wx.wxDefaultPosition, wx.wxDefaultSize,
wxaui.wxAUI_NB_DEFAULT_STYLE + wxaui.wxAUI_NB_TAB_EXTERNAL_MOVE
+ wx.wxNO_BORDER)
local current -- the currently active editor, needed by the focus selection
local function onPageChange(event)
current = event:GetSelection() -- update the active editor reference
SetEditorSelection(current)
event:Skip() -- skip to let page change
end
notebook:Connect(wx.wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, onPageChange)
notebook:Connect(wxaui.wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED, onPageChange)
notebook:Connect(wxaui.wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE,
function (event)
ClosePage(event:GetSelection())
event:Veto() -- don't propagate the event as the page is already closed
end)
notebook:Connect(wx.wxEVT_SET_FOCUS, -- Notepad tabs shouldn't be selectable,
function (event)
SetEditorSelection(current) -- select the currently active editor
end)
frame.notebook = notebook
return notebook
end
local function createBottomNotebook(frame)
-- bottomnotebook (errorlog,shellbox)
local bottomnotebook = wxaui.wxAuiNotebook(frame, wx.wxID_ANY,
wx.wxDefaultPosition, wx.wxDefaultSize,
wxaui.wxAUI_NB_DEFAULT_STYLE + wxaui.wxAUI_NB_TAB_EXTERNAL_MOVE
- wxaui.wxAUI_NB_CLOSE_ON_ACTIVE_TAB + wx.wxNO_BORDER)
local errorlog = wxstc.wxStyledTextCtrl(bottomnotebook, ID "output",
wx.wxDefaultPosition, wx.wxDefaultSize, wx.wxBORDER_STATIC)
local shellbox = wxstc.wxStyledTextCtrl(bottomnotebook, ID "shell",
wx.wxDefaultPosition, wx.wxDefaultSize, wx.wxBORDER_STATIC)
bottomnotebook:AddPage(errorlog, "Output", true)
bottomnotebook:AddPage(shellbox, "Local console", false)
bottomnotebook:Connect(wxaui.wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE,
function (event)
event:Veto() -- don't allow closing pages in this notebook
end)
frame.bottomnotebook = bottomnotebook
bottomnotebook.errorlog = errorlog
bottomnotebook.shellbox = shellbox
return bottomnotebook
end
local function createProjpanel(frame)
local projpanel = wx.wxPanel(frame,wx.wxID_ANY)
frame.projpanel = projpanel
return projpanel
end
-- ----------------------------------------------------------------------------
-- Add the child windows to the frame
local frame = createFrame()
ide.frame = frame
createToolBar(frame)
createNotebook(frame)
createProjpanel(frame)
createBottomNotebook(frame)
do
local frame = ide.frame
local mgr = frame.uimgr
mgr:AddPane(frame.toolBar, wxaui.wxAuiPaneInfo():
Name("toolBar"):Caption("Main Toolbar"):
MinSize(300,16):
ToolbarPane():Top():CloseButton(false):
LeftDockable(false):RightDockable(false):Hide())
mgr:AddPane(frame.notebook, wxaui.wxAuiPaneInfo():
Name("notebook"):
CenterPane():PaneBorder(false):Hide())
mgr:AddPane(frame.projpanel, wxaui.wxAuiPaneInfo():
Name("projpanel"):Caption("Project"):
MinSize(200,200):FloatingSize(200,400):
Left():Layer(1):Position(1):
CloseButton(true):MaximizeButton(false):PinButton(true):Hide())
mgr:AddPane(frame.bottomnotebook, wxaui.wxAuiPaneInfo():
Name("bottomnotebook"):
MinSize(200,200):FloatingSize(400,250):
Bottom():Layer(1):Position(1):
CloseButton(true):MaximizeButton(false):PinButton(true):Hide())
mgr:GetPane("toolBar"):Show(true)
mgr:GetPane("bottomnotebook"):Show(true)
mgr:GetPane("projpanel"):Show(true)
mgr:GetPane("notebook"):Show(true)
local pp = mgr:SavePerspective()
mgr.defaultPerspective = pp
mgr:Update()
end

View File

@@ -1,77 +1,78 @@
-- authors: Lomtik Software (J. Winwood & John Labenski)
-- Luxinia Dev (Eike Decker & Christoph Kubisch)
---------------------------------------------------------
-- Generate a unique new wxWindowID
local ID_IDCOUNTER = wx.wxID_HIGHEST + 1
function NewID()
ID_IDCOUNTER = ID_IDCOUNTER + 1
return ID_IDCOUNTER
end
-- File menu
ID_NEW = wx.wxID_NEW
ID_OPEN = wx.wxID_OPEN
ID_CLOSE = NewID()
ID_SAVE = wx.wxID_SAVE
ID_SAVEAS = wx.wxID_SAVEAS
ID_SAVEALL = NewID()
ID_EXIT = wx.wxID_EXIT
-- Edit menu
ID_CUT = wx.wxID_CUT
ID_COPY = wx.wxID_COPY
ID_PASTE = wx.wxID_PASTE
ID_SELECTALL = wx.wxID_SELECTALL
ID_UNDO = wx.wxID_UNDO
ID_REDO = wx.wxID_REDO
ID_AUTOCOMPLETE = NewID()
ID_AUTOCOMPLETE_ENABLE = NewID()
ID_COMMENT = NewID()
ID_FOLD = NewID()
-- Find menu
ID_FIND = wx.wxID_FIND
ID_FINDNEXT = NewID()
ID_FINDPREV = NewID()
ID_REPLACE = NewID()
ID_FIND_IN_FILES = NewID()
ID_REPLACE_IN_FILES = NewID()
ID_GOTOLINE = NewID()
ID_SORT = NewID()
-- Debug menu
ID_TOGGLEBREAKPOINT = NewID()
ID_COMPILE = NewID()
ID_RUN = NewID()
ID_ATTACH_DEBUG = NewID()
ID_START_DEBUG = NewID()
--ID_USECONSOLE = NewID()
ID_STOP_DEBUG = NewID()
ID_STEP = NewID()
ID_STEP_OVER = NewID()
ID_STEP_OUT = NewID()
ID_CONTINUE = NewID()
ID_BREAK = NewID()
--ID_VIEWCALLSTACK = NewID()
--ID_VIEWWATCHWINDOW = NewID()
ID_CLEAROUTPUT = NewID()
ID_DEBUGGER_PORT = NewID()
-- Help menu
ID_ABOUT = wx.wxID_ABOUT
-- Watch window menu items
ID_WATCH_LISTCTRL = NewID()
ID_ADDWATCH = NewID()
ID_EDITWATCH = NewID()
ID_REMOVEWATCH = NewID()
ID_EVALUATEWATCH = NewID()
ID_WORKDIR_CHOSE = NewID()
local ids = {}
function ID (name)
ids[name] = ids[name] or NewID()
return ids[name]
end
function IDget (name)
return ids[name]
end
-- authors: Lomtik Software (J. Winwood & John Labenski)
-- Luxinia Dev (Eike Decker & Christoph Kubisch)
---------------------------------------------------------
-- Generate a unique new wxWindowID
local ID_IDCOUNTER = wx.wxID_HIGHEST + 1
function NewID()
ID_IDCOUNTER = ID_IDCOUNTER + 1
return ID_IDCOUNTER
end
-- File menu
ID_NEW = wx.wxID_NEW
ID_OPEN = wx.wxID_OPEN
ID_CLOSE = NewID()
ID_SAVE = wx.wxID_SAVE
ID_SAVEAS = wx.wxID_SAVEAS
ID_SAVEALL = NewID()
ID_EXIT = wx.wxID_EXIT
-- Edit menu
ID_CUT = wx.wxID_CUT
ID_COPY = wx.wxID_COPY
ID_PASTE = wx.wxID_PASTE
ID_SELECTALL = wx.wxID_SELECTALL
ID_UNDO = wx.wxID_UNDO
ID_REDO = wx.wxID_REDO
ID_AUTOCOMPLETE = NewID()
ID_AUTOCOMPLETE_ENABLE = NewID()
ID_COMMENT = NewID()
ID_FOLD = NewID()
-- Find menu
ID_FIND = wx.wxID_FIND
ID_FINDNEXT = NewID()
ID_FINDPREV = NewID()
ID_REPLACE = NewID()
ID_FIND_IN_FILES = NewID()
ID_REPLACE_IN_FILES = NewID()
ID_GOTOLINE = NewID()
ID_SORT = NewID()
-- Debug menu
ID_TOGGLEBREAKPOINT = NewID()
ID_COMPILE = NewID()
ID_RUN = NewID()
ID_ATTACH_DEBUG = NewID()
ID_START_DEBUG = NewID()
--ID_USECONSOLE = NewID()
ID_STOP_DEBUG = NewID()
ID_STEP = NewID()
ID_STEP_OVER = NewID()
ID_STEP_OUT = NewID()
ID_CONTINUE = NewID()
ID_BREAK = NewID()
ID_TRACE = NewID()
--ID_VIEWCALLSTACK = NewID()
--ID_VIEWWATCHWINDOW = NewID()
ID_CLEAROUTPUT = NewID()
ID_DEBUGGER_PORT = NewID()
-- Help menu
ID_ABOUT = wx.wxID_ABOUT
-- Watch window menu items
ID_WATCH_LISTCTRL = NewID()
ID_ADDWATCH = NewID()
ID_EDITWATCH = NewID()
ID_REMOVEWATCH = NewID()
ID_EVALUATEWATCH = NewID()
ID_WORKDIR_CHOSE = NewID()
local ids = {}
function ID (name)
ids[name] = ids[name] or NewID()
return ids[name]
end
function IDget (name)
return ids[name]
end

View File

@@ -1,61 +1,59 @@
-- authors: Luxinia Dev (Eike Decker & Christoph Kubisch)
---------------------------------------------------------
local ide = ide
ide.iofilters["GermanUtf8Ascii"] = {
-- this function converts some utf8 character output. It's a hack.
-- Since luxinia is not utf8 prepared, this is still necessary.
-- if you wish to turn this off, edit user.lua and set this filefunction to nil
output = function (fpath, content)
local utf8escape = ("string").char(195)
-- only simple cases are handled (umlauts)
local chr = ("string").char
local charconv = {
[chr(164)] = chr(228), -- ä
[chr(182)] = chr(246), -- ö
[chr(188)] = chr(252), -- ü
[chr(132)] = chr(196), -- Ä
[chr(150)] = chr(214), -- Ö
[chr(156)] = chr(220), -- Ü
[chr(159)] = chr(223), -- ß
}
return content : gsub (utf8escape.."(.)",charconv)
end,
-- this function is another hack to read an ANSI encoded
-- file and converts the umlauts to utf8 chars
input = function (fpath, content)
local utf8escape = ("string").char(195)
local chr = ("string").char
local charconv = {
[chr(228)] = utf8escape..chr(164), -- ä
[chr(246)] = utf8escape..chr(182), -- ö
[chr(252)] = utf8escape..chr(188), -- ü
[chr(196)] = utf8escape..chr(132), -- Ä
[chr(214)] = utf8escape..chr(150), -- Ö
[chr(220)] = utf8escape..chr(156), -- Ü
[chr(223)] = utf8escape..chr(159), -- ß
}
local lst = "["
for k in pairs(charconv) do lst = lst .. k end
lst = "]"
return content:gsub(lst,charconv)
end,
}
--üäß
for i,filter in pairs(ide.iofilters) do
assert(filter.output("",filter.input("","äöüÄÖÜß")),"„”äöüÄÖÜß","UTF8-ANSI conversion failed: "..(i))
end
-- which: "input" or "output"
function GetConfigIOFilter(which)
local filtername = ide.config.editor.iofilter
return (filtername and ide.iofilters[filtername] and ide.iofilters[filtername][which])
end
-- authors: Luxinia Dev (Eike Decker & Christoph Kubisch)
---------------------------------------------------------
local ide = ide
ide.iofilters["GermanUtf8Ascii"] = {
-- this function converts some utf8 character output. It's a hack.
-- Since luxinia is not utf8 prepared, this is still necessary.
-- if you wish to turn this off, edit user.lua and set this filefunction to nil
output = function (fpath, content)
local utf8escape = ("string").char(195)
-- only simple cases are handled (umlauts)
local chr = ("string").char
local charconv = {
[chr(164)] = chr(228), -- ä
[chr(182)] = chr(246), -- ö
[chr(188)] = chr(252), -- ü
[chr(132)] = chr(196), -- Ä
[chr(150)] = chr(214), -- Ö
[chr(156)] = chr(220), -- Ü
[chr(159)] = chr(223), -- ß
}
return content : gsub (utf8escape.."(.)",charconv)
end,
-- this function is another hack to read an ANSI encoded
-- file and converts the umlauts to utf8 chars
input = function (fpath, content)
local utf8escape = ("string").char(195)
local chr = ("string").char
local charconv = {
[chr(228)] = utf8escape..chr(164), -- ä
[chr(246)] = utf8escape..chr(182), -- ö
[chr(252)] = utf8escape..chr(188), -- ü
[chr(196)] = utf8escape..chr(132), -- Ä
[chr(214)] = utf8escape..chr(150), -- Ö
[chr(220)] = utf8escape..chr(156), -- Ü
[chr(223)] = utf8escape..chr(159), -- ß
}
local lst = "["
for k in pairs(charconv) do lst = lst .. k end
lst = "]"
return content:gsub(lst,charconv)
end,
}
--üäß
for i,filter in pairs(ide.iofilters) do
assert(filter.output("",filter.input("","äöüÄÖÜß")),"„”äöüÄÖÜß","UTF8-ANSI conversion failed: "..(i))
end
-- which: "input" or "output"
function GetConfigIOFilter(which)
local filtername = ide.config.editor.iofilter
return (filtername and ide.iofilters[filtername] and ide.iofilters[filtername][which])
end

153
src/editor/markup.lua Normal file
View File

@@ -0,0 +1,153 @@
-- Copyright (C) Paul Kulchenko 2011-2012
-- update styles for comment markup
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_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 = {
[MD_MARK_BOXD] = {st=25, fg={127,0,127}, bg=comment.bg, b=true},
[MD_MARK_CODE] = {st=26, fg={127,127,127}, bg=comment.bg, fs=9},
[MD_MARK_HEAD] = {st=27, fg=comment.fg, bg=comment.bg, fn="Lucida Console", b=true},
[MD_MARK_LINK] = {st=28, fg=comment.fg, bg=comment.bg, u=true, hs={0, 0, 127}},
[MD_MARK_BOLD] = {st=29, fg=comment.fg, bg=comment.bg, b=true, fs=11},
[MD_MARK_ITAL] = {st=30, fg=comment.fg, bg=comment.bg, i=true},
[MD_MARK_MARK] = {st=31, fg=comment.fg, bg=comment.bg, v=false},
}
local MD_MARK_PTRN = '' -- combination of all markup marks that can start styling
for key,value in pairs(markup) do
styles[key] = value
if key ~= MD_MARK_MARK then MD_MARK_PTRN = MD_MARK_PTRN .. "%" .. key end
end
function MarkupHotspotClick(pos, editor)
-- check if this is "our" hotspot event
if bit.band(editor:GetStyleAt(pos),31) ~= markup[MD_MARK_LINK].st then
-- not "our" style, so nothing to do for us here
return
end
local line = editor:LineFromPosition(pos)
local tx = editor:GetLine(line)
pos = pos + 1 - editor:PositionFromLine(line) -- turn into relative position
-- find the separator on the right side of the position
local poss = string.find(tx, MD_MARK_LSEP, pos, true)
local pose = string.find(tx, MD_MARK_LINK, pos, true)
if (poss and pose) then
local text = string.sub(tx, poss+1, pose-1)
local filepath = ide.openDocuments[editor:GetId()].filePath
local _,_,shell = string.find(text, [[^macro:shell%((.*%S)%)$]])
local _,_,http = string.find(text, [[^(http:%S+)$]])
local _,_,command = string.find(text, [[^macro:(%w+)$]])
local bottomnotebook = ide.frame.bottomnotebook
if shell then
ShellExecuteCode(shell)
elseif command == 'run' then -- run the current file
ProjectRun()
elseif command == 'debug' then -- debug the current file
ProjectDebug()
elseif http then -- open the URL in a new browser window
wx.wxLaunchDefaultBrowser(http, 0)
else
-- 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
local name = wx.wxFileName(filepath):GetPath(wx.wxPATH_GET_VOLUME
+ wx.wxPATH_GET_SEPARATOR) .. text
-- load/activate file
local filename = wx.wxFileName(name)
filename:Normalize() -- remove .., ., and other similar elements
if filename:FileExists() and
(newindow or SaveModifiedDialog(editor, true) ~= wx.wxID_CANCEL) then
LoadFile(filename,not newwindow and editor or nil,true)
end
end
end
return true
end
local function ismarkup (tx)
local start = 1
while true do
-- find a separator first
local st,_,sep = string.find(tx, "(["..MD_MARK_PTRN.."])", start)
if not st then return end
local s,e,cap
if sep == MD_MARK_HEAD then
s,e,cap = string.find(tx,"^(%"..MD_MARK_HEAD..".+[%w%p])", start)
elseif sep == MD_MARK_LINK then
local any = "[^%"..MD_MARK_LINK.."%"..MD_MARK_LSEP.."]-"
s,e,cap = string.find(tx,"^(%"..MD_MARK_LINK.."[%w%p]"..any.."[%w%p]"..
"%"..MD_MARK_LSEP.."[%w%p]"..any.."[%w%p]"..
"%"..MD_MARK_LINK..")", st)
else
s,e,cap = string.find(tx,"^(%"..sep.."[%w%p][^%"..sep.."]-[%w%p]%"..sep..")", st)
if not s then s,e,cap = string.find(tx,"^(%"..sep.."[^%s%"..sep.."]%"..sep..")", st) end
end
if s then return s,e,cap,sep end
start = st+1
end
end
function MarkupStyle(editor, lines, linee)
local lines = lines or 0
if (lines < 0) then return end
-- always style to the end as there may be comments that need re-styling
-- technically, this should be GetLineCount()-1, but we want to style
-- beyond the last line to make sure it is styled correctly
local linee = linee or editor:GetLineCount()-1
local linef = editor:GetLineCount()
local iscomment = {}
for i,v in pairs(editor.spec.iscomment) do
iscomment[i] = v
end
for line=lines,linef do
local tx = editor:GetLine(line)
local ls = editor:PositionFromLine(line)
editor:StartStyling(ls, 0)
local from = 1
local off = -1
while from do
tx = string.sub(tx,from)
local f,t,w,mark = ismarkup(tx)
if (f) then
local p = ls+f+off
local s = bit.band(editor:GetStyleAt(p), 31)
if iscomment[s] then
editor:StartStyling(p, 31)
editor:SetStyling(1, markup[MD_MARK_MARK].st)
local endmark = 1
if mark == MD_MARK_HEAD then
endmark = 0
elseif mark == MD_MARK_LINK then
local pipe = w:find(MD_MARK_LSEP)
if pipe then
endmark = #w-pipe+1
end
end
editor:SetStyling(t-f-endmark, markup[mark].st or markup[MD_MARK_MARK].st)
editor:SetStyling(endmark, markup[MD_MARK_MARK].st)
end
off = off + t
end
from = t and (t+1)
end
end
end

View File

@@ -1,12 +1,12 @@
-- authors: Luxinia Dev (Eike Decker & Christoph Kubisch)
---------------------------------------------------------
local ide = ide
dofile "src/editor/menu_file.lua"
dofile "src/editor/menu_edit.lua"
dofile "src/editor/menu_search.lua"
dofile "src/editor/menu_view.lua"
dofile "src/editor/menu_project.lua"
dofile "src/editor/menu_tools.lua"
ide.frame:SetMenuBar(ide.frame.menuBar )
-- authors: Luxinia Dev (Eike Decker & Christoph Kubisch)
---------------------------------------------------------
local ide = ide
dofile "src/editor/menu_file.lua"
dofile "src/editor/menu_edit.lua"
dofile "src/editor/menu_search.lua"
dofile "src/editor/menu_view.lua"
dofile "src/editor/menu_project.lua"
dofile "src/editor/menu_tools.lua"
ide.frame:SetMenuBar(ide.frame.menuBar )

View File

@@ -1,199 +1,177 @@
-- authors: Lomtik Software (J. Winwood & John Labenski)
-- Luxinia Dev (Eike Decker & Christoph Kubisch)
---------------------------------------------------------
local ide = ide
-- ---------------------------------------------------------------------------
-- Create the Edit menu and attach the callback functions
local frame = ide.frame
local menuBar = frame.menuBar
local editMenu = wx.wxMenu{
{ ID_CUT, "Cu&t\tCtrl-X", "Cut selected text to clipboard" },
{ ID_COPY, "&Copy\tCtrl-C", "Copy selected text to the clipboard" },
{ ID_PASTE, "&Paste\tCtrl-V", "Insert clipboard text at cursor" },
{ ID_SELECTALL, "Select A&ll\tCtrl-A", "Select all text in the editor" },
{ },
{ ID_UNDO, "&Undo\tCtrl-Z", "Undo the last action" },
{ ID_REDO, "&Redo\tCtrl-Y", "Redo the last action undone" },
{ },
{ ID "edit.showtooltip", "Show &Tooltip\tCtrl+T", "Show tooltip for current position. Place cursor after opening bracket of function."},
{ ID_AUTOCOMPLETE, "Complete &Identifier\tCtrl+K", "Complete the current identifier" },
{ ID_AUTOCOMPLETE_ENABLE, "Auto complete Identifiers", "Auto complete while typing", wx.wxITEM_CHECK },
{ },
{ ID_COMMENT, "C&omment/Uncomment\tCtrl-Q", "Comment or uncomment current or selected lines"},
{ },
{ ID_FOLD, "&Fold/Unfold all\tF12", "Fold or unfold all code folds"} }
menuBar:Append(editMenu, "&Edit")
editMenu:Check(ID_AUTOCOMPLETE_ENABLE, ide.config.autocomplete)
function OnUpdateUIEditMenu(event) -- enable if there is a valid focused editor
local editor = GetEditor()
event:Enable(editor ~= nil)
end
local shellboxeditor = ide.frame.vsplitter.splitter.bottomnotebook.shellbox.input
function OnEditMenu(event)
local menu_id = event:GetId()
local editor = GetEditor()
if shellboxeditor:FindFocus():GetId() == shellboxeditor:GetId() then
editor = shellboxeditor
end
if editor == nil then return end
if menu_id == ID_CUT then editor:Cut()
elseif menu_id == ID_COPY then editor:Copy()
elseif menu_id == ID_PASTE then editor:Paste()
elseif menu_id == ID_SELECTALL then editor:SelectAll()
elseif menu_id == ID_UNDO then editor:Undo()
elseif menu_id == ID_REDO then editor:Redo()
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)
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
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)
end
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","")
--[[
local acstart = 1
local state = ""
for i=localpos,1,-1 do -- find out what should be completed
local c = linetx:sub(i,i)
if c : match "[%s]" and state~="begin" then
state = "space"
elseif c : match "[_0-9a-zA-Z]" then
if state == "space" then
acstart = i+1
break
end
state = "word"
elseif c : match(editor.spec.sep) then
state = "begin"
elseif c : match "[^%s]" then -- unknown char
acstart = i + 1
break
end
end
local lt = linetx:sub(acstart,localpos) : 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
end)
frame:Connect(ID_AUTOCOMPLETE, wx.wxEVT_UPDATE_UI, OnUpdateUIEditMenu)
frame:Connect(ID_AUTOCOMPLETE_ENABLE, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
ide.config.autocomplete = event:IsChecked()
end)
frame:Connect(ID_COMMENT, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
local editor = GetEditor()
local buf = {}
if editor:GetSelectionStart() == editor:GetSelectionEnd() then
local lineNumber = editor:GetCurrentLine()
editor:SetSelection(editor:PositionFromLine(lineNumber), editor:GetLineEndPosition(lineNumber))
end
local lc = editor.spec.linecomment
for line in string.gmatch(editor:GetSelectedText()..'\n', "(.-)\r?\n") do
if string.sub(line,1,2) == lc then
line = string.sub(line,3)
else
line = lc..line
end
table.insert(buf, line)
end
editor:ReplaceSelection(table.concat(buf,"\n"))
end)
frame:Connect(ID_COMMENT, wx.wxEVT_UPDATE_UI, OnUpdateUIEditMenu)
frame:Connect(ID_FOLD, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
FoldSome()
end)
frame:Connect(ID_FOLD, wx.wxEVT_UPDATE_UI, OnUpdateUIEditMenu)
-- authors: Lomtik Software (J. Winwood & John Labenski)
-- Luxinia Dev (Eike Decker & Christoph Kubisch)
---------------------------------------------------------
local ide = ide
-- ---------------------------------------------------------------------------
-- Create the Edit menu and attach the callback functions
local frame = ide.frame
local menuBar = frame.menuBar
local editMenu = wx.wxMenu{
{ ID_CUT, "Cu&t\tCtrl-X", "Cut selected text to clipboard" },
{ ID_COPY, "&Copy\tCtrl-C", "Copy selected text to the clipboard" },
{ ID_PASTE, "&Paste\tCtrl-V", "Insert clipboard text at cursor" },
{ ID_SELECTALL, "Select A&ll\tCtrl-A", "Select all text in the editor" },
{ },
{ ID_UNDO, "&Undo\tCtrl-Z", "Undo the last action" },
{ ID_REDO, "&Redo\tCtrl-Y", "Redo the last action undone" },
{ },
{ ID "edit.showtooltip", "Show &Tooltip\tCtrl+T", "Show tooltip for current position. Place cursor after opening bracket of function."},
{ ID_AUTOCOMPLETE, "Complete &Identifier\tCtrl+K", "Complete the current identifier" },
{ ID_AUTOCOMPLETE_ENABLE, "Auto complete Identifiers", "Auto complete while typing", wx.wxITEM_CHECK },
{ },
{ ID_COMMENT, "C&omment/Uncomment\tCtrl-Q", "Comment or uncomment current or selected lines"},
{ },
{ ID_FOLD, "&Fold/Unfold all\tF12", "Fold or unfold all code folds"},
{ ID "edit.cleardynamics", "Clear &Dynamic Words", "Resets the dynamic word list for autcompletion."},
}
menuBar:Append(editMenu, "&Edit")
editMenu:Check(ID_AUTOCOMPLETE_ENABLE, ide.config.autocomplete)
function OnUpdateUIEditMenu(event) -- enable if there is a valid focused editor
local editor = GetEditor()
event:Enable(editor ~= nil)
end
local shellboxeditor = ide.frame.bottomnotebook.shellbox
function OnEditMenu(event)
local menu_id = event:GetId()
local editor = GetEditor()
if shellboxeditor:FindFocus():GetId() == shellboxeditor:GetId() then
editor = shellboxeditor
end
if editor == nil then return end
if menu_id == ID_CUT then editor:Cut()
elseif menu_id == ID_COPY then editor:Copy()
elseif menu_id == ID_PASTE then editor:Paste()
elseif menu_id == ID_SELECTALL then editor:SelectAll()
elseif menu_id == ID_UNDO then editor:Undo()
elseif menu_id == ID_REDO then editor:Redo()
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)
frame:Connect(ID "edit.cleardynamics", wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
DynamicWordsReset()
end)
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
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)
end
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
end)
frame:Connect(ID_AUTOCOMPLETE, wx.wxEVT_UPDATE_UI, OnUpdateUIEditMenu)
frame:Connect(ID_AUTOCOMPLETE_ENABLE, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
ide.config.autocomplete = event:IsChecked()
end)
frame:Connect(ID_COMMENT, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
local editor = GetEditor()
local buf = {}
if editor:GetSelectionStart() == editor:GetSelectionEnd() then
local lineNumber = editor:GetCurrentLine()
editor:SetSelection(editor:PositionFromLine(lineNumber), editor:GetLineEndPosition(lineNumber))
end
local lc = editor.spec.linecomment
for line in string.gmatch(editor:GetSelectedText()..'\n', "(.-)\r?\n") do
if string.sub(line,1,2) == lc then
line = string.sub(line,3)
else
line = lc..line
end
table.insert(buf, line)
end
editor:ReplaceSelection(table.concat(buf,"\n"))
end)
frame:Connect(ID_COMMENT, wx.wxEVT_UPDATE_UI, OnUpdateUIEditMenu)
frame:Connect(ID_FOLD, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
FoldSome()
end)
frame:Connect(ID_FOLD, wx.wxEVT_UPDATE_UI, OnUpdateUIEditMenu)

View File

@@ -1,125 +1,116 @@
-- authors: Lomtik Software (J. Winwood & John Labenski)
-- Luxinia Dev (Eike Decker & Christoph Kubisch)
---------------------------------------------------------
local ide = ide
-- Create the File menu and attach the callback functions
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" },
{ ID_OPEN, "&Open...\tCtrl-O", "Open an existing document" },
{ ID_CLOSE, "&Close page\tCtrl+W", "Close the current editor window" },
{ },
{ ID_SAVE, "&Save\tCtrl-S", "Save the current document" },
{ ID_SAVEAS, "Save &As...\tAlt-Shift-S", "Save the current document to a file with a new name" },
{ ID_SAVEALL, "Save A&ll...\tCtrl-Shift-S", "Save all open documents" },
{ },
--{ ID "file.recentfiles", "Recent files",},
{ },
{ ID_EXIT, "E&xit\tAlt-X", "Exit Program" }})
menuBar:Append(fileMenu, "&File")
local filehistorymenu = wx.wxMenu({})
local filehistory = wx.wxMenuItem(fileMenu,ID"file.recentfiles","Recent files", "File history", wx.wxITEM_NORMAL,filehistorymenu)
fileMenu:Insert(8,filehistory)
function UpdateFileHistoryUI(list)
-- remove all at first
for i=1,filehistorymenu:GetMenuItemCount() do
filehistorymenu:Delete( ID("file.recentfiles."..i))
end
for i=1,#list do
local file = list[i].filename
local item = wx.wxMenuItem(filehistorymenu, ID("file.recentfiles."..i),file,"")
filehistorymenu:Append(item)
end
end
for i=1,ide.config.filehistorylength do
frame:Connect(ID("file.recentfiles."..i), wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
local item = filehistorymenu:FindItemByPosition(i-1)
local filename = item:GetLabel()
LoadFile(filename)
--DisplayOutput("selected "..tostring(filename).."\n")
end
)
end
frame:Connect(ID_NEW, wx.wxEVT_COMMAND_MENU_SELECTED, NewFile)
frame:Connect(ID_OPEN, wx.wxEVT_COMMAND_MENU_SELECTED, OpenFile)
frame:Connect(ID_SAVE, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
local editor = GetEditor()
local id = editor:GetId()
local filePath = openDocuments[id].filePath
if (filePath) then
SaveFile(editor, filePath)
else
SaveFileAs(editor)
end
end)
frame:Connect(ID_SAVE, wx.wxEVT_UPDATE_UI,
function (event)
local editor = GetEditor()
if editor then
local id = editor:GetId()
if openDocuments[id] then
event:Enable(openDocuments[id].isModified or not openDocuments[id].filePath)
end
end
end)
frame:Connect(ID_SAVEAS, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
local editor = GetEditor()
SaveFileAs(editor)
end)
frame:Connect(ID_SAVEAS, wx.wxEVT_UPDATE_UI,
function (event)
local editor = GetEditor()
event:Enable(editor ~= nil)
end)
frame:Connect(ID_SAVEALL, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
SaveAll()
end)
frame:Connect(ID_SAVEALL, wx.wxEVT_UPDATE_UI,
function (event)
local atLeastOneModifiedDocument = false
for id, document in pairs(openDocuments) do
if document.isModified then
atLeastOneModifiedDocument = true
break
end
end
event:Enable(atLeastOneModifiedDocument)
end)
frame:Connect(ID_CLOSE, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
local editor = GetEditor()
local id = editor:GetId()
if SaveModifiedDialog(editor, true) ~= wx.wxID_CANCEL then
RemovePage(openDocuments[id].index)
end
end)
frame:Connect(ID_CLOSE, wx.wxEVT_UPDATE_UI,
function (event)
event:Enable((GetEditor() ~= nil) and (debugger.server == nil))
end)
frame:Connect( ID_EXIT, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
if not SaveOnExit(true) then return end
frame:Close() -- will handle wxEVT_CLOSE_WINDOW
CloseWatchWindow()
end)
-- authors: Lomtik Software (J. Winwood & John Labenski)
-- Luxinia Dev (Eike Decker & Christoph Kubisch)
---------------------------------------------------------
local ide = ide
-- Create the File menu and attach the callback functions
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" },
{ ID_OPEN, "&Open...\tCtrl-O", "Open an existing document" },
{ ID_CLOSE, "&Close page\tCtrl+W", "Close the current editor window" },
{ },
{ ID_SAVE, "&Save\tCtrl-S", "Save the current document" },
{ ID_SAVEAS, "Save &As...\tAlt-Shift-S", "Save the current document to a file with a new name" },
{ ID_SAVEALL, "Save A&ll...\tCtrl-Shift-S", "Save all open documents" },
{ },
--{ ID "file.recentfiles", "Recent files",},
{ },
{ ID_EXIT, "E&xit\tAlt-X", "Exit Program" }})
menuBar:Append(fileMenu, "&File")
local filehistorymenu = wx.wxMenu({})
local filehistory = wx.wxMenuItem(fileMenu,ID"file.recentfiles","Recent files", "File history", wx.wxITEM_NORMAL,filehistorymenu)
fileMenu:Insert(8,filehistory)
function UpdateFileHistoryUI(list)
-- remove all at first
for i=1,filehistorymenu:GetMenuItemCount() do
filehistorymenu:Delete( ID("file.recentfiles."..i))
end
for i=1,#list do
local file = list[i].filename
local item = wx.wxMenuItem(filehistorymenu, ID("file.recentfiles."..i),file,"")
filehistorymenu:Append(item)
end
end
for i=1,ide.config.filehistorylength do
frame:Connect(ID("file.recentfiles."..i), wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
local item = filehistorymenu:FindItemByPosition(i-1)
local filename = item:GetLabel()
LoadFile(filename)
end
)
end
frame:Connect(ID_NEW, wx.wxEVT_COMMAND_MENU_SELECTED, NewFile)
frame:Connect(ID_OPEN, wx.wxEVT_COMMAND_MENU_SELECTED, OpenFile)
frame:Connect(ID_SAVE, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
local editor = GetEditor()
local id = editor:GetId()
local filePath = openDocuments[id].filePath
if (filePath) then
SaveFile(editor, filePath)
else
SaveFileAs(editor)
end
end)
frame:Connect(ID_SAVE, wx.wxEVT_UPDATE_UI,
function (event)
local editor = GetEditor()
if editor then
local id = editor:GetId()
if openDocuments[id] then
event:Enable(openDocuments[id].isModified or not openDocuments[id].filePath)
end
end
end)
frame:Connect(ID_SAVEAS, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
local editor = GetEditor()
SaveFileAs(editor)
end)
frame:Connect(ID_SAVEAS, wx.wxEVT_UPDATE_UI,
function (event)
local editor = GetEditor()
event:Enable(editor ~= nil)
end)
frame:Connect(ID_SAVEALL, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
SaveAll()
end)
frame:Connect(ID_SAVEALL, wx.wxEVT_UPDATE_UI,
function (event)
local atLeastOneModifiedDocument = false
for id, document in pairs(openDocuments) do
if document.isModified then
atLeastOneModifiedDocument = true
break
end
end
event:Enable(atLeastOneModifiedDocument)
end)
frame:Connect(ID_CLOSE, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
ClosePage() -- this will find the current editor
end)
frame:Connect(ID_CLOSE, wx.wxEVT_UPDATE_UI,
function (event)
event:Enable((GetEditor() ~= nil) and (debugger.server == nil))
end)
frame:Connect(ID_EXIT, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
if not SaveOnExit(true) then return end
frame:Close() -- will handle wxEVT_CLOSE_WINDOW
DebuggerCloseWatchWindow()
end)

View File

@@ -1,331 +1,368 @@
-- authors: Lomtik Software (J. Winwood & John Labenski)
-- Luxinia Dev (Eike Decker & Christoph Kubisch)
---------------------------------------------------------
-- Create the Debug menu and attach the callback functions
local frame = ide.frame
local menuBar = frame.menuBar
local vsplitter= frame.vsplitter
local sidenotebook = vsplitter.sidenotebook
local splitter = vsplitter.splitter
local errorlog = splitter.bottomnotebook.errorlog
local notebook = splitter.notebook
local openDocuments = ide.openDocuments
local debugger = ide.debugger
local filetree = ide.filetree
--------------
-- Interpreters
local interpreters = {}
local lastinterpreter
for i,v in pairs(ide.interpreters) do
interpreters[ID ("debug.interpreter."..i)] = v
v.fname = i
lastinterpreter = v.name
end
assert(lastinterpreter,"no interpreters defined")
local debugMenu = wx.wxMenu{
{ ID_RUN, "&Run\tShift-F5", "Execute the current project/file" },
{ ID_COMPILE, "&Compile\tF7", "Test compile the Lua file" },
--{ ID_ATTACH_DEBUG, "&Attach\tShift-F6", "Allow a client to start a debugging session" },
{ ID_START_DEBUG, "&Start Debugging\tF5", "Start a debugging session" },
--{ ID_USECONSOLE, "Console", "Use console when running", wx.wxITEM_CHECK },
{ },
{ ID_STOP_DEBUG, "S&top Debugging\tShift-F12", "Stop and end the debugging session" },
{ 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_CONTINUE, "Co&ntinue\tF6", "Run the program at full speed" },
{ ID_BREAK, "&Break", "Stop execution of the program at the next executed line of code" },
{ },
{ ID_TOGGLEBREAKPOINT, "Toggle &Breakpoint\tF9", "Toggle Breakpoint" },
--{ ID "view.debug.callstack", "V&iew Call Stack", "View the LUA call stack" },
{ ID "view.debug.watches", "View &Watch Window", "View the Watch window" },
{ },
{ ID_CLEAROUTPUT, "C&lear Output Window", "Clear the output window before compiling or debugging", wx.wxITEM_CHECK },
--{ }, { ID_DEBUGGER_PORT, "Set debugger socket port...", "Chose what port to use for debugger sockets." },
}
local targetargs = {}
for id,inter in pairs(interpreters) do
table.insert(targetargs,{id,inter.name,inter.description,wx.wxITEM_CHECK})
end
local target = wx.wxMenu{
unpack(targetargs)
}
local targetworkdir = wx.wxMenu{
{ID "debug.projectdir.choose","Choose ..."},
{ID "debug.projectdir.fromfile","From current filepath"},
{},
{ID "debug.projectdir.currentdir",""}
}
debugMenu:Append(0,"Lua &interpreter",target,"Set the interpreter to be used")
debugMenu:Append(0,"Project directory",targetworkdir,"Set the project directory to be used")
menuBar:Append(debugMenu, "&Project")
--menuBar:Check(ID_USECONSOLE, true)
function UpdateProjectDir(projdir,skiptree)
ide.config.path.projectdir = projdir
menuBar:SetLabel(ID "debug.projectdir.currentdir",projdir)
frame:SetStatusText(projdir)
if (not skiptree) then
ide.filetree:UpdateProjectDir(projdir)
end
end
UpdateProjectDir(ide.config.path.projectdir)
-- interpreter setup
local curinterpreterid = IDget("debug.interpreter."..ide.config.interpreter) or
ID ("debug.interpreter."..lastinterpreter)
ide.config.interpreterClass = interpreters[curinterpreterid]
menuBar:Check(curinterpreterid, true)
local function selectInterpreter (id)
for i,inter in pairs(interpreters) do
menuBar:Check(i, false)
end
menuBar:Check(id, true)
curinterpreterid = id
ide.config.interpreter = interpreters[id].fname
ide.config.interpreterClass = interpreters[id]
ReloadLuaAPI()
end
local function evSelectInterpreter (event)
local chose = event:GetId()
selectInterpreter(chose)
end
for id,inter in pairs(interpreters) do
frame:Connect(id,wx.wxEVT_COMMAND_MENU_SELECTED,evSelectInterpreter)
end
function SetInterpreter(name)
local id = IDget("debug.interpreter."..name)
if (not interpreters[id]) then return end
selectInterpreter(id)
end
local function projChoose(event)
local editor = GetEditor()
local id = editor:GetId()
local saved = false
local fn = wx.wxFileName(openDocuments[id].filePath or "")
fn:Normalize() -- want absolute path for dialog
local projectdir = ide.config.path.projectdir
--filePicker:Show(true)
--local diag = wx.wxDialog()
--diag:ShowModal(true)
local filePicker = wx.wxDirDialog(frame, "Chose a project directory",
projectdir~="" and projectdir or wx.wxGetCwd(),wx.wxFLP_USE_TEXTCTRL)
local res = filePicker:ShowModal(true)
--for i,v in pairs(wx) do if v == res then print(i) end end
--print(res)
if res == wx.wxID_OK then
UpdateProjectDir(filePicker:GetPath())
end
--filePicker:Destroy()
return true
end
frame:Connect(ID "debug.projectdir.choose", wx.wxEVT_COMMAND_MENU_SELECTED,
projChoose)
frame:Connect(ID "debug.projectdir.choose", wx.wxEVT_COMMAND_BUTTON_CLICKED,
projChoose)
local function projFromFile(event)
local editor = GetEditor()
if not editor then return end
local id = editor:GetId()
local filepath = openDocuments[id].filePath
if not filepath then return end
local fn = wx.wxFileName(filepath)
fn:Normalize() -- want absolute path for dialog
UpdateProjectDir(interpreters[curinterpreterid]:fprojdir(fn))
end
frame:Connect(ID "debug.projectdir.fromfile", wx.wxEVT_COMMAND_MENU_SELECTED,
projFromFile)
function RunInterpreter(wfilename, script)
-- SaveAll()
local editor = GetEditor()
-- test compile it before we run it, if successful then ask to save
-- only compile if lua api
if (editor.spec.apitype and
editor.spec.apitype == "lua" and
not CompileProgram(editor)) then
return
end
if not SaveIfModified(editor) then
return
end
local interpreter = interpreters[curinterpreterid]
interpreter:frun(wfilename, script)
end
frame:Connect(ID_TOGGLEBREAKPOINT, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
local editor = GetEditor()
local line = editor:LineFromPosition(editor:GetCurrentPos())
ToggleDebugMarker(editor, line)
end)
frame:Connect(ID_TOGGLEBREAKPOINT, wx.wxEVT_UPDATE_UI, OnUpdateUIEditMenu)
frame:Connect(ID_COMPILE, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
local editor = GetEditor()
CompileProgram(editor)
end)
frame:Connect(ID_COMPILE, wx.wxEVT_UPDATE_UI, OnUpdateUIEditMenu)
frame:Connect(ID_RUN, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
RunInterpreter(wx.wxFileName(openDocuments[GetEditor():GetId()].filePath));
end)
frame:Connect(ID_RUN, wx.wxEVT_UPDATE_UI,
function (event)
local editor = GetEditor()
event:Enable((debugger.server == nil) and (editor ~= nil))
end)
frame:Connect(ID_ATTACH_DEBUG, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
debugger.connect()
end)
frame:Connect(ID_ATTACH_DEBUG, wx.wxEVT_UPDATE_UI,
function (event)
local editor = GetEditor()
event:Enable((debugger.server == nil) and (editor ~= nil))
end)
frame:Connect(ID_START_DEBUG, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
local editorDir = string.gsub(ide.editorFilename:gsub("[^/\\]+$",""),"\\","/")
RunInterpreter(wx.wxFileName(openDocuments[GetEditor():GetId()].filePath),
"package.path=package.path..';"..editorDir.."lualibs/?/?.lua';"..
"package.cpath=package.cpath..';"..editorDir.."bin/clibs/?.dll';"..
"require 'mobdebug'; io.stdout:setvbuf('no'); mobdebug.loop('" .. wx.wxGetHostName().."',"..debugger.portnumber..")");
end)
frame:Connect(ID_START_DEBUG, wx.wxEVT_UPDATE_UI,
function (event)
local editor = GetEditor()
event:Enable((debugger.server == nil) and (editor ~= nil))
end)
frame:Connect(ID_STOP_DEBUG, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
ClearAllCurrentLineMarkers()
debugger.run("exit")
end)
frame:Connect(ID_STOP_DEBUG, wx.wxEVT_UPDATE_UI,
function (event)
local editor = GetEditor()
event:Enable((debugger.server ~= nil) and (editor ~= nil))
end)
frame:Connect(ID_STEP, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
ClearAllCurrentLineMarkers()
debugger.run("step")
end)
frame:Connect(ID_STEP, wx.wxEVT_UPDATE_UI,
function (event)
local editor = GetEditor()
event:Enable((debugger.server ~= nil) and (not debugger.running) and (editor ~= nil))
end)
frame:Connect(ID_STEP_OVER, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
ClearAllCurrentLineMarkers()
debugger.run("over")
end)
frame:Connect(ID_STEP_OVER, wx.wxEVT_UPDATE_UI,
function (event)
local editor = GetEditor()
event:Enable((debugger.server ~= nil) and (not debugger.running) and (editor ~= nil))
end)
frame:Connect(ID_STEP_OUT, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
ClearAllCurrentLineMarkers()
debugger.run("out")
end)
frame:Connect(ID_STEP_OUT, wx.wxEVT_UPDATE_UI,
function (event)
event:Enable((debugger.server ~= nil) and (not debugger.running))
end)
frame:Connect(ID_CONTINUE, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
ClearAllCurrentLineMarkers()
debugger.run("run")
end)
frame:Connect(ID_CONTINUE, wx.wxEVT_UPDATE_UI,
function (event)
event:Enable((debugger.server ~= nil) and (not debugger.running))
end)
frame:Connect(ID_BREAK, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
if debugger.server then
debugger.server:Break()
end
end)
frame:Connect(ID_BREAK, wx.wxEVT_UPDATE_UI,
function (event)
event:Enable((debugger.server ~= nil) and debugger.running)
end)
frame:Connect(ID_DEBUGGER_PORT, wx.wxEVT_COMMAND_MENU_SELECTED,
function(event)
end)
frame:Connect(ID_DEBUGGER_PORT, wx.wxEVT_UPDATE_UI,
function(event)
event:Enable(debugger.server == nil)
end)
frame:Connect(wx.wxEVT_IDLE,
function(event)
debugger.update()
end)
frame:Connect(ID "view.debug.callstack", wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
if debugger.server then
debugger.server:DisplayStackDialog(frame)
end
end)
frame:Connect(ID "view.debug.callstack", wx.wxEVT_UPDATE_UI,
function (event)
event:Enable((debugger.server ~= nil) and (not debugger.running))
end)
frame:Connect(ID "view.debug.watches", wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
if not debugger.watchWindow then
CreateWatchWindow()
end
end)
frame:Connect(ID "view.debug.watches", wx.wxEVT_UPDATE_UI,
function (event)
event:Enable((debugger.server ~= nil) and (not debugger.running))
end)
-- authors: Lomtik Software (J. Winwood & John Labenski)
-- Luxinia Dev (Eike Decker & Christoph Kubisch)
---------------------------------------------------------
local ide = ide
-- Create the Debug menu and attach the callback functions
local frame = ide.frame
local menuBar = frame.menuBar
local openDocuments = ide.openDocuments
local debugger = ide.debugger
local filetree = ide.filetree
local bottomnotebook = frame.bottomnotebook
local uimgr = frame.uimgr
------------------------
-- Interpreters and Menu
local targetMenu
local interpreters = {}
local lastinterpreter
do
local interpreternames = {}
local lkinterpreters = {}
for i,v in pairs(ide.interpreters) do
interpreters[ID ("debug.interpreter."..i)] = v
v.fname = i
lastinterpreter = i
table.insert(interpreternames,v.name)
lkinterpreters[v.name] = i
end
assert(lastinterpreter,"no interpreters defined")
table.sort(interpreternames)
local targetargs = {}
for i,v in ipairs(interpreternames) do
local id = ID ("debug.interpreter."..lkinterpreters[v])
local inter = interpreters[id]
table.insert(targetargs,{id,inter.name,inter.description,wx.wxITEM_CHECK})
end
targetMenu = wx.wxMenu(targetargs)
end
local debugTab = {
{ ID_RUN, "&Run\tF6", "Execute the current project/file" },
{ ID_COMPILE, "&Compile\tF7", "Test compile the Lua file" },
{ ID_START_DEBUG, "Start &Debugging\tF5", "Start a debugging session" },
{ ID_ATTACH_DEBUG, "&Start Debugger Server\tShift-F6", "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_TRACE, "Tr&ace", "Trace execution showing each executed line" },
{ ID_BREAK, "&Break", "Stop execution of the program at the next executed line of code" },
{ },
{ ID_TOGGLEBREAKPOINT, "Toggle &Breakpoint\tF9", "Toggle Breakpoint" },
--{ ID "view.debug.callstack", "V&iew Call Stack", "View the call stack" },
{ },
{ ID_CLEAROUTPUT, "C&lear Output Window", "Clear the output window before compiling or debugging", wx.wxITEM_CHECK },
}
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 targetDirMenu = wx.wxMenu{
{ID "debug.projectdir.choose","Choose ..."},
{ID "debug.projectdir.fromfile","From current filepath"},
{},
{ID "debug.projectdir.currentdir",""}
}
debugMenu:Append(0,"Lua &interpreter",targetMenu,"Set the interpreter to be used")
debugMenu:Append(0,"Project directory",targetDirMenu,"Set the project directory to be used")
menuBar:Append(debugMenu, "&Project")
-----------------------------
-- Project directory handling
function ProjectUpdateProjectDir(projdir,skiptree)
ide.config.path.projectdir = projdir
menuBar:SetLabel(ID "debug.projectdir.currentdir",projdir)
frame:SetStatusText(projdir)
if (not skiptree) then
ide.filetree:updateProjectDir(projdir)
end
end
ProjectUpdateProjectDir(ide.config.path.projectdir)
local function projChoose(event)
local editor = GetEditor()
local saved = false
local fn = wx.wxFileName(
editor and openDocuments[editor:GetId()].filePath or "")
fn:Normalize() -- want absolute path for dialog
local projectdir = ide.config.path.projectdir
local filePicker = wx.wxDirDialog(frame, "Chose a project directory",
projectdir~="" and projectdir or wx.wxGetCwd(),wx.wxFLP_USE_TEXTCTRL)
local res = filePicker:ShowModal(true)
if res == wx.wxID_OK then
ProjectUpdateProjectDir(filePicker:GetPath())
end
return true
end
frame:Connect(ID "debug.projectdir.choose", wx.wxEVT_COMMAND_MENU_SELECTED,
projChoose)
frame:Connect(ID "debug.projectdir.choose", wx.wxEVT_COMMAND_BUTTON_CLICKED,
projChoose)
local function projFromFile(event)
local editor = GetEditor()
if not editor then return end
local id = editor:GetId()
local filepath = openDocuments[id].filePath
if not filepath then return end
local fn = wx.wxFileName(filepath)
fn:Normalize() -- want absolute path for dialog
if ide.interpreter then ProjectUpdateProjectDir(ide.interpreter:fprojdir(fn)) end
end
frame:Connect(ID "debug.projectdir.fromfile", wx.wxEVT_COMMAND_MENU_SELECTED,
projFromFile)
------------------------------------
-- Interpreter Selection and Running
local function selectInterpreter(id)
for i,inter in pairs(interpreters) do
menuBar:Check(i, false)
end
menuBar:Check(id, true)
ide.interpreter = interpreters[id]
ReloadLuaAPI()
end
function ProjectSetInterpreter(name)
local id = IDget("debug.interpreter."..name)
if (not interpreters[id]) then return end
selectInterpreter(id)
end
local function evSelectInterpreter (event)
local chose = event:GetId()
selectInterpreter(chose)
end
for id,inter in pairs(interpreters) do
frame:Connect(id,wx.wxEVT_COMMAND_MENU_SELECTED,evSelectInterpreter)
end
do
local defaultid = (
IDget("debug.interpreter."..ide.config.interpreter) or
ID ("debug.interpreter."..lastinterpreter)
)
ide.interpreter = interpreters[defaultid]
menuBar:Check(defaultid, true)
end
local function getNameToRun()
local editor = GetEditor()
-- test compile it before we run it, if successful then ask to save
-- only compile if lua api
if (editor.spec.apitype and
editor.spec.apitype == "lua" and
not CompileProgram(editor)) then
return
end
local id = editor:GetId()
if not openDocuments[id].filePath then SetDocumentModified(id, true) end
if not SaveIfModified(editor) then return end
return wx.wxFileName(openDocuments[id].filePath)
end
local function activateOutput()
if not ide.config.activateoutput then return end
-- show output/errorlog pane
uimgr:GetPane("bottomnotebook"):Show(true)
uimgr:Update()
-- activate output/errorlog window
local index = bottomnotebook:GetPageIndex(bottomnotebook.errorlog)
if bottomnotebook:GetSelection() ~= index then
bottomnotebook:SetSelection(index)
end
end
local function runInterpreter(wfilename, withdebugger)
activateOutput()
ClearAllCurrentLineMarkers()
if not wfilename then return end
local pid = ide.interpreter:frun(wfilename, withdebugger)
debugger.pid = pid
end
function ProjectRun()
runInterpreter(getNameToRun())
end
function ProjectDebug()
if (debugger.server ~= nil) then
if (not debugger.running) then
ClearAllCurrentLineMarkers()
debugger.run()
end
else
runInterpreter(getNameToRun(), true)
end
end
-----------------------
-- Actions
frame:Connect(ID_TOGGLEBREAKPOINT, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
local editor = GetEditor()
local line = editor:LineFromPosition(editor:GetCurrentPos())
DebuggerToggleBreakpoint(editor, line)
end)
frame:Connect(ID_TOGGLEBREAKPOINT, wx.wxEVT_UPDATE_UI,
function (event)
local editor = GetEditor()
event:Enable((ide.interpreter) and (ide.interpreter.hasdebugger) and (editor ~= nil))
end)
frame:Connect(ID_COMPILE, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
local editor = GetEditor()
activateOutput()
CompileProgram(editor)
end)
frame:Connect(ID_COMPILE, wx.wxEVT_UPDATE_UI,
function (event)
local editor = GetEditor()
event:Enable((debugger.server == nil and debugger.pid == nil) and (editor ~= nil))
end)
frame:Connect(ID_RUN, wx.wxEVT_COMMAND_MENU_SELECTED, ProjectRun)
frame:Connect(ID_RUN, wx.wxEVT_UPDATE_UI,
function (event)
local editor = GetEditor()
event:Enable((debugger.server == nil and debugger.pid == nil) and (editor ~= nil))
end)
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,
function (event)
local editor = GetEditor()
event:Enable((ide.interpreter) and (ide.interpreter.fattachdebug) and
(not debugger.listening) and (debugger.server == nil) and (editor ~= nil))
end)
frame:Connect(ID_START_DEBUG, wx.wxEVT_COMMAND_MENU_SELECTED, ProjectDebug)
frame:Connect(ID_START_DEBUG, wx.wxEVT_UPDATE_UI,
function (event)
local editor = GetEditor()
event:Enable((ide.interpreter) and (ide.interpreter.hasdebugger) and
((debugger.server == nil and debugger.pid == nil) or (debugger.server ~= nil and not debugger.running)) and (editor ~= nil))
local label = (debugger.server ~= nil)
and debugMenuRun.continue or debugMenuRun.start
if debugMenu:GetLabel(ID_START_DEBUG) ~= label then
debugMenu:SetLabel(ID_START_DEBUG, label)
end
end)
frame:Connect(ID_STOP_DEBUG, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
ClearAllCurrentLineMarkers()
if debugger.server then debugger.terminate() end
if debugger.pid then DebuggerKillClient() end
end)
frame:Connect(ID_STOP_DEBUG, wx.wxEVT_UPDATE_UI,
function (event)
local editor = GetEditor()
event:Enable((debugger.server ~= nil or debugger.pid ~= nil) and (editor ~= nil))
local label = (debugger.server == nil and debugger.pid ~= nil)
and debugMenuStop.process or debugMenuStop.debugging
if debugMenu:GetLabel(ID_STOP_DEBUG) ~= label then
debugMenu:SetLabel(ID_STOP_DEBUG, label)
end
end)
frame:Connect(ID_STEP, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
ClearAllCurrentLineMarkers()
debugger.step()
end)
frame:Connect(ID_STEP, wx.wxEVT_UPDATE_UI,
function (event)
local editor = GetEditor()
event:Enable((debugger.server ~= nil) and (not debugger.running) and (editor ~= nil))
end)
frame:Connect(ID_STEP_OVER, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
ClearAllCurrentLineMarkers()
debugger.over()
end)
frame:Connect(ID_STEP_OVER, wx.wxEVT_UPDATE_UI,
function (event)
local editor = GetEditor()
event:Enable((debugger.server ~= nil) and (not debugger.running) and (editor ~= nil))
end)
frame:Connect(ID_STEP_OUT, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
ClearAllCurrentLineMarkers()
debugger.out()
end)
frame:Connect(ID_STEP_OUT, wx.wxEVT_UPDATE_UI,
function (event)
local editor = GetEditor()
event:Enable((debugger.server ~= nil) and (not debugger.running) and (editor ~= nil))
end)
frame:Connect(ID_TRACE, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
ClearAllCurrentLineMarkers()
debugger.trace()
end)
frame:Connect(ID_TRACE, wx.wxEVT_UPDATE_UI,
function (event)
local editor = GetEditor()
event:Enable((debugger.server ~= nil) and (not debugger.running) and (editor ~= nil))
end)
frame:Connect(ID_BREAK, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
if debugger.server then
debugger.breaknow()
end
end)
frame:Connect(ID_BREAK, wx.wxEVT_UPDATE_UI,
function (event)
local editor = GetEditor()
event:Enable((debugger.server ~= nil) and (debugger.running) and (editor ~= nil))
end)
--[[
frame:Connect(ID "view.debug.callstack", wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
if debugger.server then
DebuggerCreateStackWindow()
end
end)
frame:Connect(ID "view.debug.callstack", wx.wxEVT_UPDATE_UI,
function (event)
event:Enable((debugger.server ~= nil) and (not debugger.running))
end)
]]
frame:Connect(wx.wxEVT_IDLE,
function(event)
if (debugger.update) then
debugger.update()
end
end)

View File

@@ -1,92 +1,90 @@
-- authors: Lomtik Software (J. Winwood & John Labenski)
-- Luxinia Dev (Eike Decker & Christoph Kubisch)
---------------------------------------------------------
local ide = ide
-- Create the Search menu and attach the callback functions
local frame = ide.frame
local menuBar = frame.menuBar
local findReplace = ide.findReplace
local findMenu = wx.wxMenu{
{ ID_FIND, "&Find\tCtrl-F", "Find the specified text" },
{ ID_FINDNEXT, "Find &Next\tF3", "Find the next occurrence of the specified text" },
{ ID_FINDPREV, "Find &Previous\tShift-F3", "Repeat the search backwards in the file" },
{ ID_REPLACE, "&Replace\tCtrl-H", "Replaces the specified text with different text" },
{ },
{ ID_FIND_IN_FILES, "Find &In Files\tCtrl-Shift-F", " Find specified text in files"},
{ ID_REPLACE_IN_FILES, "Re&place In Files\tCtrl-Shift-H", " Replace specified text in files"},
{ },
{ ID_GOTOLINE, "&Goto line\tCtrl-G", "Go to a selected line" },
{ },
{ ID_SORT, "&Sort", "Sort selected lines"}}
menuBar:Append(findMenu, "&Search")
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_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_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_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_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)
frame:Connect(ID_FINDPREV, wx.wxEVT_COMMAND_MENU_SELECTED, function (event) findReplace:GetSelectedString() findReplace:FindString(true) end)
frame:Connect(ID_FINDPREV, wx.wxEVT_UPDATE_UI, function (event) findReplace:HasText() end)
-------------------- Find replace end
frame:Connect(ID_GOTOLINE, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
local editor = GetEditor()
local linecur = editor:LineFromPosition(editor:GetCurrentPos())
local linemax = editor:LineFromPosition(editor:GetLength()) + 1
local linenum = wx.wxGetNumberFromUser( "Enter line number",
"1 .. "..tostring(linemax),
"Goto Line",
linecur, 1, linemax,
frame)
if linenum > 0 then
editor:GotoLine(linenum-1)
end
end)
frame:Connect(ID_GOTOLINE, wx.wxEVT_UPDATE_UI, OnUpdateUIEditMenu)
frame:Connect(ID_SORT, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
local editor = GetEditor()
local buf = {}
for line in string.gmatch(editor:GetSelectedText()..'\n', "(.-)\r?\n") do
table.insert(buf, line)
end
if #buf > 0 then
table.sort(buf)
editor:ReplaceSelection(table.concat(buf,"\n"))
end
end)
frame:Connect(ID_SORT, wx.wxEVT_UPDATE_UI, OnUpdateUIEditMenu)
-- authors: Lomtik Software (J. Winwood & John Labenski)
-- Luxinia Dev (Eike Decker & Christoph Kubisch)
---------------------------------------------------------
local ide = ide
-- Create the Search menu and attach the callback functions
local frame = ide.frame
local menuBar = frame.menuBar
local findReplace = ide.findReplace
local findMenu = wx.wxMenu{
{ ID_FIND, "&Find\tCtrl-F", "Find the specified text" },
{ ID_FINDNEXT, "Find &Next\tF3", "Find the next occurrence of the specified text" },
{ ID_FINDPREV, "Find &Previous\tShift-F3", "Repeat the search backwards in the file" },
{ ID_REPLACE, "&Replace\tCtrl-H", "Replaces the specified text with different text" },
{ },
{ ID_FIND_IN_FILES, "Find &In Files\tCtrl-Shift-F", " Find specified text in files"},
{ ID_REPLACE_IN_FILES, "Re&place In Files\tCtrl-Shift-H", " Replace specified text in files"},
{ },
{ ID_GOTOLINE, "&Goto line\tCtrl-G", "Go to a selected line" },
{ },
{ ID_SORT, "&Sort", "Sort selected lines"}}
menuBar:Append(findMenu, "&Search")
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_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_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_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_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)
frame:Connect(ID_FINDPREV, wx.wxEVT_COMMAND_MENU_SELECTED, function (event) findReplace:GetSelectedString() findReplace:FindString(true) end)
frame:Connect(ID_FINDPREV, wx.wxEVT_UPDATE_UI, function (event) findReplace:HasText() end)
-------------------- Find replace end
frame:Connect(ID_GOTOLINE, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
local editor = GetEditor()
local linecur = editor:LineFromPosition(editor:GetCurrentPos())
local linemax = editor:LineFromPosition(editor:GetLength()) + 1
local linenum = wx.wxGetNumberFromUser( "Enter line number",
"1 .. "..tostring(linemax),
"Goto Line",
linecur, 1, linemax,
frame)
if linenum > 0 then
editor:GotoLine(linenum-1)
end
end)
frame:Connect(ID_GOTOLINE, wx.wxEVT_UPDATE_UI, OnUpdateUIEditMenu)
frame:Connect(ID_SORT, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
local editor = GetEditor()
local buf = {}
for line in string.gmatch(editor:GetSelectedText()..'\n', "(.-)\r?\n") do
table.insert(buf, line)
end
if #buf > 0 then
table.sort(buf)
editor:ReplaceSelection(table.concat(buf,"\n"))
end
end)
frame:Connect(ID_SORT, wx.wxEVT_UPDATE_UI, OnUpdateUIEditMenu)

View File

@@ -1,94 +1,91 @@
-- authors: Luxinia Dev (Eike Decker & Christoph Kubisch)
---------------------------------------------------------
local ide = ide
local frame = ide.frame
local menuBar = frame.menuBar
local openDocuments = ide.openDocuments
--[=[
-- tool definition
-- main entries are optional
tool = {
fnmenu = function(frame,menubar),
-- can be used for init
-- and custom menu
exec = {
-- quick exec action
name = "",
description = "",
fn = function(wxfilename,projectdir),
}
}
]=]
local toolArgs = {{},}
-- fill in tools that have a automatic execution
-- function
do
local cnt = 1
local maxcnt = 10
local tools = {}
for name,tool in pairs(ide.tools) do
if (tool.exec and tool.exec.name) then
tool.fname = name
table.insert(tools,tool)
end
end
table.sort(tools,function(a,b) return a.exec.name < b.exec.name end)
-- todo config specifc ignore/priority list
for i,tool in ipairs(tools) do
local exec = tool.exec
if (exec and cnt < maxcnt and exec.name and exec.fn and exec.description) then
local id = ID("tools.exec."..tool.fname)
table.insert(toolArgs,{id , exec.name.."\tCtrl-"..cnt, exec.description})
-- flag it
tool._execid = id
cnt = cnt + 1
end
end
end
-- Build Menu
local toolMenu = wx.wxMenu{
unpack(toolArgs)
}
menuBar:Append(toolMenu, "&Tools")
-- connect auto execs
do
for name,tool in pairs(ide.tools) do
if (tool._execid) then
frame:Connect(tool._execid, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
local editor = GetEditor()
if (not editor) then return end
local id = editor:GetId()
local saved = false
local fn = wx.wxFileName(openDocuments[id].filePath or "")
fn:Normalize()
tool.exec.fn(fn,ide.config.path.projectdir)
return true
end)
end
end
end
-- Generate Custom Menus/Init
for name,tool in pairs(ide.tools) do
if (tool.fninit) then
tool.fninit(frame,menuBar)
end
end
-- authors: Luxinia Dev (Eike Decker & Christoph Kubisch)
---------------------------------------------------------
local ide = ide
local frame = ide.frame
local menuBar = frame.menuBar
local openDocuments = ide.openDocuments
--[=[
-- tool definition
-- main entries are optional
tool = {
fnmenu = function(frame,menubar),
-- can be used for init
-- and custom menu
exec = {
-- quick exec action
name = "",
description = "",
fn = function(wxfilename,projectdir),
}
}
]=]
local toolArgs = {{},}
local cnt = 1
-- fill in tools that have a automatic execution
-- function
do
local maxcnt = 10
local tools = {}
for name,tool in pairs(ide.tools) do
if (tool.exec and tool.exec.name) then
tool.fname = name
table.insert(tools,tool)
end
end
table.sort(tools,function(a,b) return a.exec.name < b.exec.name end)
-- todo config specifc ignore/priority list
for i,tool in ipairs(tools) do
local exec = tool.exec
if (exec and cnt < maxcnt and exec.name and exec.fn and exec.description) then
local id = ID("tools.exec."..tool.fname)
table.insert(toolArgs,{id , exec.name.."\tCtrl-"..cnt, exec.description})
-- flag it
tool._execid = id
cnt = cnt + 1
end
end
end
if (cnt > 1) then
-- Build Menu
local toolMenu = wx.wxMenu{
unpack(toolArgs)
}
menuBar:Append(toolMenu, "&Tools")
-- connect auto execs
for name,tool in pairs(ide.tools) do
if (tool._execid) then
frame:Connect(tool._execid, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
local editor = GetEditor()
if (not editor) then return end
local id = editor:GetId()
local saved = false
local fn = wx.wxFileName(openDocuments[id].filePath or "")
fn:Normalize()
tool.exec.fn(fn,ide.config.path.projectdir)
return true
end)
end
end
end
-- Generate Custom Menus/Init
for name,tool in pairs(ide.tools) do
if (tool.fninit) then
tool.fninit(frame,menuBar)
end
end

View File

@@ -1,54 +1,57 @@
-- authors: Lomtik Software (J. Winwood & John Labenski)
-- Luxinia Dev (Eike Decker & Christoph Kubisch)
---------------------------------------------------------
local ide = ide
local frame = ide.frame
local menuBar = frame.menuBar
local vsplitter= frame.vsplitter
local sidenotebook = vsplitter.sidenotebook
local splitter = vsplitter.splitter
local errorlog = splitter.bottomnotebook.errorlog
local notebook = splitter.notebook
local debugger = ide.debugger
local viewMenu = wx.wxMenu{
{ ID "view.preferences", "&Preferences...", "Brings up dialog for settings (TODO)" },
{ },
{ ID "view.filetree.show", "View &FileTree Window", "View or Hide the filetree window",wx.wxITEM_CHECK },
{ ID "view.output.show", "View &Output/Shell Window", "View or Hide the output/shell window",wx.wxITEM_CHECK },
{ },
{ ID "view.style.loadconfig", "&Load Config Style...", "Load and apply style from config file (must contain .styles)"},
}
menuBar:Append(viewMenu, "&View")
menuBar:Check(ID "view.filetree.show", true)
menuBar:Check(ID "view.output.show", true)
frame:Connect(ID "view.preferences", wx.wxEVT_COMMAND_MENU_SELECTED,preferencesDialog.show)
frame:Connect(ID "view.style.loadconfig", wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
LoadConfigStyle()
end)
frame:Connect(ID "view.output.show", wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
local w, h = frame:GetClientSizeWH()
if splitter:IsSplit() then
ide.config.view.splitterheight = h - splitter:GetSashPosition()
splitter:Unsplit()
else
splitter:SplitHorizontally(notebook, splitter.bottomnotebook, h - ide.config.view.splitterheight)
end
end)
frame:Connect(ID "view.filetree.show", wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
if vsplitter:IsSplit() then
ide.config.view.vsplitterpos = vsplitter:GetSashPosition()
vsplitter:Unsplit(sidenotebook)
else
vsplitter:SplitVertically(sidenotebook,splitter,ide.config.view.vsplitterpos)
end
end)
-- authors: Lomtik Software (J. Winwood & John Labenski)
-- Luxinia Dev (Eike Decker & Christoph Kubisch)
---------------------------------------------------------
local ide = ide
local frame = ide.frame
local menuBar = frame.menuBar
local uimgr = frame.uimgr
local debugger = ide.debugger
local viewMenu = wx.wxMenu{
-- NYI { ID "view.preferences", "&Preferences...", "Brings up dialog for settings (TODO)" },
-- NYI { },
{ ID "view.filetree.show", "Project/&FileTree Window\tCtrl-Alt-P", "View the project/filetree window" },
{ ID "view.output.show", "&Output/Shell Window\tCtrl-Alt-O", "View the output/shell window" },
{ ID "view.debug.watches", "&Watch Window", "View the Watch window" },
{ },
{ ID "view.defaultlayout", "&Default Layout", "Reset to default layout"},
{ ID "view.fullscreen", "Full &Screen\tCtrl-Alt-F", "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")
--frame:Connect(ID "view.preferences", wx.wxEVT_COMMAND_MENU_SELECTED,preferencesDialog.show)
frame:Connect(ID "view.style.loadconfig", wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
LoadConfigStyle()
end)
frame:Connect(ID "view.defaultlayout", wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
uimgr:LoadPerspective(uimgr.defaultPerspective)
uimgr:Update()
end)
frame:Connect(ID "view.output.show", wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
uimgr:GetPane("bottomnotebook"):Show(true)
uimgr:Update()
end)
frame:Connect(ID "view.filetree.show", wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
uimgr:GetPane("projpanel"):Show(true)
uimgr:Update()
end)
frame:Connect(ID "view.fullscreen", wx.wxEVT_COMMAND_MENU_SELECTED,
function (event) ShowFullScreen(not frame:IsFullScreen()) end)
frame:Connect(ID "view.debug.watches", wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
if not debugger.watchWindow then
DebuggerCreateWatchWindow()
end
end)

View File

@@ -1,222 +1,244 @@
-- authors: Lomtik Software (J. Winwood & John Labenski)
-- Luxinia Dev (Eike Decker & Christoph Kubisch)
---------------------------------------------------------
local ide = ide
local frame = ide.frame
local splitter = frame.vsplitter.splitter
local notebook = splitter.notebook
local bottomnotebook = splitter.bottomnotebook
local errorlog = bottomnotebook.errorlog
-------
-- setup errorlog
errorlog:Show(true)
errorlog:SetFont(ide.ofont)
errorlog:StyleSetFont(wxstc.wxSTC_STYLE_DEFAULT, ide.ofont)
errorlog:StyleClearAll()
errorlog:SetMarginWidth(1, 16) -- marker margin
errorlog:SetMarginType(1, wxstc.wxSTC_MARGIN_SYMBOL);
errorlog:MarkerDefine(CURRENT_LINE_MARKER, wxstc.wxSTC_MARK_ARROWS, wx.wxBLACK, wx.wxWHITE)
errorlog:SetReadOnly(true)
StylesApplyToEditor(ide.config.stylesoutshell,errorlog,ide.ofont,ide.ofontItalic)
function ClearOutput(event)
errorlog:SetReadOnly(false)
errorlog:ClearAll()
errorlog:SetReadOnly(true)
end
function DisplayOutputNoMarker(...)
local message = ""
local cnt = select('#',...)
for i=1,cnt do
local v = select(i,...)
message = message..tostring(v)..(i<cnt and "\t" or "")
end
errorlog:SetReadOnly(false)
errorlog:AppendText(message)
errorlog:SetReadOnly(true)
errorlog:GotoPos(errorlog:GetLength())
end
function DisplayOutput(...)
errorlog:MarkerAdd(errorlog:GetLineCount()-1, CURRENT_LINE_MARKER)
DisplayOutputNoMarker(...)
end
local streamins = {}
local streamerrs = {}
local customprocs = {}
function CommandLineRunning(uid)
for pid,custom in pairs(customprocs) do
if (custom.uid == uid and custom.proc and custom.proc.Exists(tonumber(tostring(pid))) )then
return true
end
end
return false
end
function CommandLineToShell(uid,state)
for pid,custom in pairs(customprocs) do
if (custom.uid == uid and custom.proc and custom.proc.Exists(tonumber(tostring(pid))) )then
if (streamins[pid]) then streamins[pid].toshell = state end
if (streamerrs[pid]) then streamerrs[pid].toshell = state end
return true
end
end
end
function CommandLineRun(cmd,wdir,tooutput,nohide,stringcallback,uid,endcallback)
if (not cmd) then return true end
local exename = string.gsub(cmd, "\\", "/")
exename = string.match(exename,'%/*([^%/]+%.%w+)') or exename
exename = string.match(exename,'%/*([^%/]+%.%w+)[%s%"]') or exename
uid = uid or exename
if (CommandLineRunning(uid)) then
DisplayOutput("Conflicting Process still running: "..cmd.."\n")
return true
end
DisplayOutput("Running program: "..cmd.."\n")
local pid = -1
local proc = nil
local customproc
if (tooutput) then
customproc = wx.wxProcess(errorlog)
customproc:Redirect()
proc = customproc
end
-- manipulate working directory
local oldcwd
if (wdir) then
oldcwd = wx.wxFileName.GetCwd()
oldcwd = wx.wxFileName.SetCwd(wdir) and oldcwd
end
-- launch process
local pid = proc and wx.wxExecute(cmd, wx.wxEXEC_ASYNC + (nohide and wx.wxEXEC_NOHIDE or 0),proc) or
wx.wxExecute(cmd, wx.wxEXEC_ASYNC + (nohide and wx.wxEXEC_NOHIDE or 0))
if (oldcwd) then
wx.wxFileName.SetCwd(oldcwd)
end
-- check process
if not pid or pid == -1 then
DisplayOutputNoMarker("Unknown ERROR Running program!\n")
customproc = nil
return true
else
DisplayOutputNoMarker("Process: "..uid.." pid:"..tostring(pid).."\n")
customprocs[pid] = {proc=customproc, uid=uid, endcallback=endcallback}
end
local streamin = proc and proc:GetInputStream()
local streamerr = proc and proc:GetErrorStream()
if (streamin) then
streamins[pid] = {stream=streamin, callback=stringcallback}
end
if (streamerr) then
streamerrs[pid] = {stream=streamerr, callback=stringcallback}
end
end
local function getStreams()
local function displayStream(tab)
for i,v in pairs(tab) do
while(v.stream:CanRead()) do
local str = v.stream:Read(4096)
local pfn
if (v.callback) then
str,pfn = v.callback(str)
end
if (v.toshell) then
DisplayShell(str)
else
DisplayOutputNoMarker(str)
end
pfn = pfn and pfn()
end
end
end
displayStream(streamins)
displayStream(streamerrs)
end
errorlog:Connect(wx.wxEVT_END_PROCESS, function(event)
local pid = event:GetPid()
if (pid ~= -1) then
getStreams()
streamins[pid] = nil
streamerrs[pid] = nil
if (customprocs[pid].endcallback) then
customprocs[pid].endcallback()
end
customprocs[pid] = nil
DisplayOutput("Program finished ("..pid..").\n")
end
end)
errorlog:Connect(wx.wxEVT_IDLE, function(event)
if (#streamins or #streamerrs) then
getStreams()
end
end)
local jumptopatterns = {
-- <filename>(line,linepos):
"%s*([%w:/%\\_%-%.]+)%((%d+),(%d+)%)%s*:",
-- <filename>(line):
"%s*([%w:/%\\_%-%.]+)%((%d+).*%)%s*:",
-- <filename>:line:
"%s*([%w:/%\\_%-%.]+):(%d+)%s*:",
--[string "<filename>"]:line:
'.*%[string "([%w:/%\\_%-%.]+)"%]:(%d+)%s*:',
}
errorlog:Connect(wxstc.wxEVT_STC_DOUBLECLICK,
function(event)
local line = errorlog:GetCurrentLine()
local linetx = errorlog:GetLine(line)
-- try to detect a filename + line
-- in linetx
local fname
local jumpline
local jumplinepos
for i,pattern in ipairs(jumptopatterns) do
fname,jumpline,jumplinepos = linetx:match(pattern)
if (fname and jumpline) then
break
end
end
if (fname and jumpline) then
LoadFile(fname,nil,true)
local editor = GetEditor()
if (editor) then
jumpline = tonumber(jumpline)
jumplinepos = tonumber(jumplinepos)
--editor:ScrollToLine(jumpline)
editor:GotoPos(editor:PositionFromLine(math.max(0,jumpline-1)) + (jumplinepos and (math.max(0,jumplinepos-1)) or 0))
editor:SetFocus()
end
end
end)
-- authors: Lomtik Software (J. Winwood & John Labenski)
-- Luxinia Dev (Eike Decker & Christoph Kubisch)
---------------------------------------------------------
local ide = ide
local frame = ide.frame
local notebook = frame.notebook
local bottomnotebook = frame.bottomnotebook
local errorlog = bottomnotebook.errorlog
-------
-- setup errorlog
errorlog:Show(true)
errorlog:SetFont(ide.ofont)
errorlog:StyleSetFont(wxstc.wxSTC_STYLE_DEFAULT, ide.ofont)
errorlog:StyleClearAll()
errorlog:SetMarginWidth(1, 16) -- marker margin
errorlog:SetMarginType(1, wxstc.wxSTC_MARGIN_SYMBOL);
errorlog:MarkerDefine(CURRENT_LINE_MARKER, wxstc.wxSTC_MARK_ARROWS, wx.wxBLACK, wx.wxWHITE)
errorlog:SetReadOnly(true)
StylesApplyToEditor(ide.config.stylesoutshell,errorlog,ide.ofont,ide.ofontItalic)
function ClearOutput(event)
errorlog:SetReadOnly(false)
errorlog:ClearAll()
errorlog:SetReadOnly(true)
end
function DisplayOutputNoMarker(...)
local message = ""
local cnt = select('#',...)
for i=1,cnt do
local v = select(i,...)
message = message..tostring(v)..(i<cnt and "\t" or "")
end
errorlog:SetReadOnly(false)
errorlog:AppendText(message)
errorlog:SetReadOnly(true)
errorlog:GotoPos(errorlog:GetLength())
end
function DisplayOutput(...)
errorlog:MarkerAdd(errorlog:GetLineCount()-1, CURRENT_LINE_MARKER)
DisplayOutputNoMarker(...)
end
local streamins = {}
local streamerrs = {}
local customprocs = {}
function CommandLineRunning(uid)
for pid,custom in pairs(customprocs) do
if (custom.uid == uid and custom.proc and custom.proc.Exists(tonumber(tostring(pid))) )then
return true
end
end
return false
end
function CommandLineToShell(uid,state)
for pid,custom in pairs(customprocs) do
if ((pid == uid or custom.uid == uid) and custom.proc and custom.proc.Exists(tonumber(tostring(pid))) )then
if (streamins[pid]) then streamins[pid].toshell = state end
if (streamerrs[pid]) then streamerrs[pid].toshell = state end
return true
end
end
end
-- logic to "unhide" wxwidget window using winapi
pcall(function () return require 'winapi' end)
local pid = nil
local function unHideWxWindow(pidAssign)
if pidAssign ~= nil then
pid = pidAssign > 0 and pidAssign or nil
end
if pid and winapi then
local win = winapi.find_window_ex(function(w)
return w:get_process():get_pid() == pid
and w:get_class_name() == 'wxWindowClassNR'
end)
if win and not win:is_visible() then
win:show()
pid = nil
end
end
end
function CommandLineRun(cmd,wdir,tooutput,nohide,stringcallback,uid,endcallback)
if (not cmd) then return end
local exename = string.gsub(cmd, "\\", "/")
exename = string.match(exename,'%/*([^%/]+%.%w+)') or exename
exename = string.match(exename,'%/*([^%/]+%.%w+)[%s%"]') or exename
uid = uid or exename
if (CommandLineRunning(uid)) then
DisplayOutput("Conflicting Process still running: "..cmd.."\n")
return
end
DisplayOutput("Running program: "..cmd.."\n")
local pid = -1
local proc = nil
local customproc
if (tooutput) then
customproc = wx.wxProcess(errorlog)
customproc:Redirect()
proc = customproc
end
-- manipulate working directory
local oldcwd
if (wdir) then
oldcwd = wx.wxFileName.GetCwd()
oldcwd = wx.wxFileName.SetCwd(wdir) and oldcwd
end
-- launch process
local pid = (proc and wx.wxExecute(cmd, wx.wxEXEC_ASYNC + (nohide and wx.wxEXEC_NOHIDE or 0),proc) or
wx.wxExecute(cmd, wx.wxEXEC_ASYNC + (nohide and wx.wxEXEC_NOHIDE or 0)))
if (oldcwd) then
wx.wxFileName.SetCwd(oldcwd)
end
-- check process
if not pid or pid == -1 then
DisplayOutputNoMarker("Unknown ERROR Running program!\n")
customproc = nil
return
else
DisplayOutput(
"Process: "..uid..", pid:"..tostring(pid)..
", started in '"..(wdir and wdir or wx.wxFileName.GetCwd()).."'\n")
customprocs[pid] = {proc=customproc, uid=uid, endcallback=endcallback}
end
local streamin = proc and proc:GetInputStream()
local streamerr = proc and proc:GetErrorStream()
if (streamin) then
streamins[pid] = {stream=streamin, callback=stringcallback}
end
if (streamerr) then
streamerrs[pid] = {stream=streamerr, callback=stringcallback}
end
unHideWxWindow(pid)
return pid
end
local function getStreams()
local function displayStream(tab)
for i,v in pairs(tab) do
while(v.stream:CanRead()) do
local str = v.stream:Read(4096)
local pfn
if (v.callback) then
str,pfn = v.callback(str)
end
if (v.toshell) then
DisplayShell(str)
else
DisplayOutputNoMarker(str)
end
pfn = pfn and pfn()
end
end
end
displayStream(streamins)
displayStream(streamerrs)
end
errorlog:Connect(wx.wxEVT_END_PROCESS, function(event)
local pid = event:GetPid()
if (pid ~= -1) then
getStreams()
streamins[pid] = nil
streamerrs[pid] = nil
if (customprocs[pid].endcallback) then
customprocs[pid].endcallback()
end
customprocs[pid] = nil
unHideWxWindow(0)
DisplayOutput("Program finished (pid: "..pid..").\n")
end
end)
errorlog:Connect(wx.wxEVT_IDLE, function(event)
if (#streamins or #streamerrs) then
getStreams()
end
unHideWxWindow()
end)
local jumptopatterns = {
-- <filename>(line,linepos):
"%s*([%w:/%\\_%-%.]+)%((%d+),(%d+)%)%s*:",
-- <filename>(line):
"%s*([%w:/%\\_%-%.]+)%((%d+).*%)%s*:",
-- <filename>:line:
"%s*([%w:/%\\_%-%.]+):(%d+)%s*:",
--[string "<filename>"]:line:
'.*%[string "([%w:/%\\_%-%.]+)"%]:(%d+)%s*:',
}
errorlog:Connect(wxstc.wxEVT_STC_DOUBLECLICK,
function(event)
local line = errorlog:GetCurrentLine()
local linetx = errorlog:GetLine(line)
-- try to detect a filename + line
-- in linetx
local fname
local jumpline
local jumplinepos
for i,pattern in ipairs(jumptopatterns) do
fname,jumpline,jumplinepos = linetx:match(pattern)
if (fname and jumpline) then
break
end
end
if (fname and jumpline) then
LoadFile(fname,nil,true)
local editor = GetEditor()
if (editor) then
jumpline = tonumber(jumpline)
jumplinepos = tonumber(jumplinepos)
--editor:ScrollToLine(jumpline)
editor:GotoPos(editor:PositionFromLine(math.max(0,jumpline-1)) + (jumplinepos and (math.max(0,jumplinepos-1)) or 0))
editor:SetFocus()
end
end
end)

View File

@@ -4,302 +4,300 @@ local ide = ide
-- the preferences dialog
preferencesDialog = {
category = {};
uifactory = {};
category = {};
uifactory = {};
}
local cats = preferencesDialog.category
local function checkstring (v,m)
if type(v)~="string" then
error(m.." ("..type(v)..")")
end
if type(v)~="string" then
error(m.." ("..type(v)..")")
end
end
function preferencesDialog.addCategory(category)
checkstring(category.title,"Invalid category title")
checkstring(category.category,"No category")
assert(not cats[category.category],"Category already declared")
cats[category.category] = category
cats[#cats+1] = category
category.order = category.order or #cats
category.entry = {}
checkstring(category.title,"Invalid category title")
checkstring(category.category,"No category")
assert(not cats[category.category],"Category already declared")
cats[category.category] = category
cats[#cats+1] = category
category.order = category.order or #cats
category.entry = {}
end
function preferencesDialog.addPage(page)
assert(page.category and cats[page.category],"Invalid category given")
checkstring(page.title,"Invalid title")
local c = cats[page.category]
c.entry[#c.entry+1] = page
page.order = page.order or #c.entry
assert(page.category and cats[page.category],"Invalid category given")
checkstring(page.title,"Invalid title")
local c = cats[page.category]
c.entry[#c.entry+1] = page
page.order = page.order or #c.entry
end
function preferencesDialog.uifactory.space(page,layout,element)
layout.currentx = layout.currentx + element.space
return layout
layout.currentx = layout.currentx + element.space
return layout
end
function preferencesDialog.uifactory.group(page,layout,element)
local margin = element.margin or 6
local nl = {
currentx = margin;
currenty = margin+ (element.title and 12 or 8);
maxsizex = 0;
maxsizey = 0;
minwidth = element.minwidth or 0;
minheight = element.minheight or 0;
margin = margin;
layout = layout;
parent = wx.wxStaticBox(layout.parent,wx.wxID_ANY,element.title or "",
wx.wxPoint(layout.currentx,layout.currenty),
wx.wxDefaultSize, element.borderstyle and wx["wxBORDER_"..element.borderstyle:upper()] or 0);
}
return nl
local margin = element.margin or 6
local nl = {
currentx = margin;
currenty = margin+ (element.title and 12 or 8);
maxsizex = 0;
maxsizey = 0;
minwidth = element.minwidth or 0;
minheight = element.minheight or 0;
margin = margin;
layout = layout;
parent = wx.wxStaticBox(layout.parent,wx.wxID_ANY,element.title or "",
wx.wxPoint(layout.currentx,layout.currenty),
wx.wxDefaultSize, element.borderstyle and wx["wxBORDER_"..element.borderstyle:upper()] or 0);
}
return nl
end
function preferencesDialog.uifactory.finishgroup(page,layout,element)
local l = layout.layout
layout.maxsizex = math.max(layout.minwidth,layout.maxsizex + layout.margin)
layout.maxsizey = math.max(layout.minheight,layout.maxsizey + layout.margin)
l.maxsizey = math.max(l.maxsizey,layout.maxsizey+l.currenty)
l.currentx = l.currentx + layout.maxsizex
l.maxsizex = math.max(l.maxsizex,l.currentx)
layout.parent:SetSize(wx.wxSize(layout.maxsizex,layout.maxsizey))
return l
local l = layout.layout
layout.maxsizex = math.max(layout.minwidth,layout.maxsizex + layout.margin)
layout.maxsizey = math.max(layout.minheight,layout.maxsizey + layout.margin)
l.maxsizey = math.max(l.maxsizey,layout.maxsizey+l.currenty)
l.currentx = l.currentx + layout.maxsizex
l.maxsizex = math.max(l.maxsizex,l.currentx)
layout.parent:SetSize(wx.wxSize(layout.maxsizex,layout.maxsizey))
return l
end
local function pos(layout) return layout.currentx,layout.currenty end
local function fitin(el,layout)
local x,y = pos(layout)
local sz = el:GetBestFittingSize()
el:SetSize(sz)
layout.maxsizex = math.max(x+sz:GetWidth(),layout.maxsizex)
layout.maxsizey = math.max(y+sz:GetHeight(),layout.maxsizey)
layout.currentx = x+sz:GetWidth()
return layout
local x,y = pos(layout)
local sz = el:GetBestFittingSize()
el:SetSize(sz)
layout.maxsizex = math.max(x+sz:GetWidth(),layout.maxsizex)
layout.maxsizey = math.max(y+sz:GetHeight(),layout.maxsizey)
layout.currentx = x+sz:GetWidth()
return layout
end
function preferencesDialog.uifactory.combobox(page,layout,element,value)
local x,y = pos(layout)
local id = ID("view.preferences.dialog.page."..page.title.."."..element.name)
local cbox = wx.wxComboBox(layout.parent,id,"",wx.wxPoint(x,y-4),wx.wxDefaultSize,
wx.wxArrayString(),wx.wxCB_READONLY)
if value then
for i=1,#value do
cbox:Append(value[i])
end
end
return fitin(cbox,layout)
local x,y = pos(layout)
local id = ID("view.preferences.dialog.page."..page.title.."."..element.name)
local cbox = wx.wxComboBox(layout.parent,id,"",wx.wxPoint(x,y-4),wx.wxDefaultSize,
wx.wxArrayString(),wx.wxCB_READONLY)
if value then
for i=1,#value do
cbox:Append(value[i])
end
end
return fitin(cbox,layout)
end
function preferencesDialog.uifactory.dirpicker(page,layout,element,value)
local x,y = pos(layout)
local id = ID("view.preferences.dialog.page."..page.title.."."..element.name)
local picker = wx.wxDirPickerCtrl(layout.parent,id,value or "",element.title or "",wx.wxPoint(x,y-4))
return fitin(picker,layout)
local x,y = pos(layout)
local id = ID("view.preferences.dialog.page."..page.title.."."..element.name)
local picker = wx.wxDirPickerCtrl(layout.parent,id,value or "",element.title or "",wx.wxPoint(x,y-4))
return fitin(picker,layout)
end
function preferencesDialog.uifactory.edit (page,layout,element,value)
local x,y = pos(layout)
local id = ID("view.preferences.dialog.page."..page.title.."."..element.name)
local edit = wx.wxTextCtrl(layout.parent,id,value or (""..x..","..y), wx.wxPoint(x,y-4))
return fitin(edit,layout)
local x,y = pos(layout)
local id = ID("view.preferences.dialog.page."..page.title.."."..element.name)
local edit = wx.wxTextCtrl(layout.parent,id,value or (""..x..","..y), wx.wxPoint(x,y-4))
return fitin(edit,layout)
end
function preferencesDialog.uifactory.linebreak(page,layout,element)
layout.currentx = layout.margin or 0
layout.currenty = layout.maxsizey + (element.space or 0)
return layout
layout.currentx = layout.margin or 0
layout.currenty = layout.maxsizey + (element.space or 0)
return layout
end
function preferencesDialog.uifactory.checkbox (page,layout,element, value)
local x,y = pos(layout)
local id = ID("view.preferences.dialog.page."..page.title.."."..element.name)
local cbox = wx.wxCheckBox(layout.parent,id,element.title,wx.wxPoint(x,y))
if value then cbox:SetValue(value) end
return fitin(cbox,layout)
local x,y = pos(layout)
local id = ID("view.preferences.dialog.page."..page.title.."."..element.name)
local cbox = wx.wxCheckBox(layout.parent,id,element.title,wx.wxPoint(x,y))
if value then cbox:SetValue(value) end
return fitin(cbox,layout)
end
function preferencesDialog.uifactory.static(page,layout,element)
local x,y = pos(layout)
local static = wx.wxStaticText(layout.parent,wx.wxID_ANY,element.title,wx.wxPoint(x,y))
return fitin(static,layout)
local x,y = pos(layout)
local static = wx.wxStaticText(layout.parent,wx.wxID_ANY,element.title,wx.wxPoint(x,y))
return fitin(static,layout)
end
function preferencesDialog.uifactory.space(page,layout,element)
layout.currentx = layout.currentx + element.space
return layout
layout.currentx = layout.currentx + element.space
return layout
end
function preferencesDialog.uifactory.group(page,layout,element)
local margin = element.margin or 6
local nl = {
currentx = margin;
currenty = margin+ (element.title and 12 or 8);
maxsizex = 0;
maxsizey = 0;
minwidth = element.minwidth or 0;
minheight = element.minheight or 0;
margin = margin;
layout = layout;
parent = wx.wxStaticBox(layout.parent,wx.wxID_ANY,element.title or "",
wx.wxPoint(layout.currentx,layout.currenty),
wx.wxDefaultSize, element.borderstyle and wx["wxBORDER_"..element.borderstyle:upper()] or 0);
}
return nl
local margin = element.margin or 6
local nl = {
currentx = margin;
currenty = margin+ (element.title and 12 or 8);
maxsizex = 0;
maxsizey = 0;
minwidth = element.minwidth or 0;
minheight = element.minheight or 0;
margin = margin;
layout = layout;
parent = wx.wxStaticBox(layout.parent,wx.wxID_ANY,element.title or "",
wx.wxPoint(layout.currentx,layout.currenty),
wx.wxDefaultSize, element.borderstyle and wx["wxBORDER_"..element.borderstyle:upper()] or 0);
}
return nl
end
function preferencesDialog.uifactory.finishgroup(page,layout,element)
local l = layout.layout
layout.maxsizex = math.max(layout.minwidth,layout.maxsizex + layout.margin)
layout.maxsizey = math.max(layout.minheight,layout.maxsizey + layout.margin)
l.maxsizey = math.max(l.maxsizey,layout.maxsizey+l.currenty)
l.currentx = l.currentx + layout.maxsizex
l.maxsizex = math.max(l.maxsizex,l.currentx)
layout.parent:SetSize(wx.wxSize(layout.maxsizex,layout.maxsizey))
return l
local l = layout.layout
layout.maxsizex = math.max(layout.minwidth,layout.maxsizex + layout.margin)
layout.maxsizey = math.max(layout.minheight,layout.maxsizey + layout.margin)
l.maxsizey = math.max(l.maxsizey,layout.maxsizey+l.currenty)
l.currentx = l.currentx + layout.maxsizex
l.maxsizex = math.max(l.maxsizex,l.currentx)
layout.parent:SetSize(wx.wxSize(layout.maxsizex,layout.maxsizey))
return l
end
function preferencesDialog.uifactory.linebreak(page,layout,element)
layout.currentx = layout.margin or 0
layout.currenty = layout.maxsizey + (element.space or 0)
return layout
layout.currentx = layout.margin or 0
layout.currenty = layout.maxsizey + (element.space or 0)
return layout
end
function preferencesDialog.uifactory.checkbox (page,layout,element, value)
local x,y = layout.currentx,layout.currenty
local id = ID("view.preferences.dialog.page."..page.title.."."..element.name)
local cbox = wx.wxCheckBox(layout.parent,id,element.title,wx.wxPoint(x,y))
local sz = cbox:GetBestFittingSize()
cbox:SetSize(sz)
layout.maxsizex = math.max(x+sz:GetWidth(),layout.maxsizex)
layout.maxsizey = math.max(y+sz:GetHeight(),layout.maxsizey)
layout.currentx = layout.maxsizex
if value then cbox:SetValue(value) end
return layout
local x,y = layout.currentx,layout.currenty
local id = ID("view.preferences.dialog.page."..page.title.."."..element.name)
local cbox = wx.wxCheckBox(layout.parent,id,element.title,wx.wxPoint(x,y))
local sz = cbox:GetBestFittingSize()
cbox:SetSize(sz)
layout.maxsizex = math.max(x+sz:GetWidth(),layout.maxsizex)
layout.maxsizey = math.max(y+sz:GetHeight(),layout.maxsizey)
layout.currentx = layout.maxsizex
if value then cbox:SetValue(value) end
return layout
end
function preferencesDialog.uifactory.static(page,layout,element)
local x,y = layout.currentx,layout.currenty
local static = wx.wxStaticText(layout.parent,wx.wxID_ANY,element.title,wx.wxPoint(x,y))
local sz = static:GetBestFittingSize()
static:SetSize(sz)
layout.maxsizex = math.max(x+sz:GetWidth(),layout.maxsizex)
layout.maxsizey = math.max(y+sz:GetHeight(),layout.maxsizey)
layout.currentx = layout.maxsizex
return layout
local x,y = layout.currentx,layout.currenty
local static = wx.wxStaticText(layout.parent,wx.wxID_ANY,element.title,wx.wxPoint(x,y))
local sz = static:GetBestFittingSize()
static:SetSize(sz)
layout.maxsizex = math.max(x+sz:GetWidth(),layout.maxsizex)
layout.maxsizey = math.max(y+sz:GetHeight(),layout.maxsizey)
layout.currentx = layout.maxsizex
return layout
end
local function showpage(panel,page)
--TODO: layout the page, load values, etc
local data = page.onload()
local layout = page.layout
local layoutdata = {
currentx = 0;
currenty = 0;
maxsizex = 0;
maxsizey = 0;
parent = panel;
}
for i,el in ipairs(layout) do
assert(preferencesDialog.uifactory[el.type],"Unknown ui type type")
layoutdata = assert(
preferencesDialog.uifactory[el.type](page,layoutdata,el,data[el.name])
)
end
panel:SetSize(layoutdata.maxsizex,layoutdata.maxsizey)
--print(layoutdata.maxsizex,layoutdata.maxsizey)
--TODO: layout the page, load values, etc
local data = page.onload()
local layout = page.layout
local layoutdata = {
currentx = 0;
currenty = 0;
maxsizex = 0;
maxsizey = 0;
parent = panel;
}
for i,el in ipairs(layout) do
assert(preferencesDialog.uifactory[el.type],"Unknown ui type type")
layoutdata = assert(
preferencesDialog.uifactory[el.type](page,layoutdata,el,data[el.name])
)
end
panel:SetSize(layoutdata.maxsizex,layoutdata.maxsizey)
--print(layoutdata.maxsizex,layoutdata.maxsizey)
end
function preferencesDialog.show(event)
local dialog = wx.wxDialog(ide.frame, ID "view.preferences.dialog","Preferences")
local id_btn_ok = ID "view.preferences.dialog.button.ok"
local id_btn_cancel = ID "view.preferences.dialog.button.cancel"
local id_btn_apply = ID "view.preferences.dialog.button.apply"
local panel_buttons = wx.wxPanel(dialog,ID "view.preferences.dialog.buttonpanel")
local btn_ok = wx.wxButton(panel_buttons,id_btn_ok, "OK")
local btn_cancel = wx.wxButton(panel_buttons,id_btn_cancel, "Cancel")
local btn_apply = wx.wxButton(panel_buttons,id_btn_apply, "Apply")
dialog:Connect(id_btn_cancel, wx.wxEVT_COMMAND_BUTTON_CLICKED,
function (event)
dialog:EndModal(0)
end)
dialog:Connect(id_btn_ok, wx.wxEVT_COMMAND_BUTTON_CLICKED,
function (event)
dialog:EndModal(0)
end)
local panel = wx.wxPanel(dialog,ID "view.preferences.dialog.panel",
wx.wxDefaultPosition, wx.wxSize(600,400))
local projtree = wx.wxTreeCtrl(panel, ID "view.preferences.dialog.panel.tree",
wx.wxDefaultPosition, wx.wxSize(180,400),
wx.wxTR_HAS_BUTTONS + wx.wxTR_SINGLE + wx.wxTR_HIDE_ROOT)
local preferencesPage = wx.wxPanel(panel,ID "view.preferences.dialog.page",
wx.wxDefaultPosition, wx.wxSize(500,400))
local panelsizer = wx.wxBoxSizer(wx.wxHORIZONTAL)
panelsizer:Add(projtree,0,wx.wxALL + wx.wxALIGN_LEFT + wx.wxTOP + wx.wxBOTTOM,0)
panelsizer:AddSpacer(5)
panelsizer:Add(preferencesPage)
panel:SetSizer(panelsizer)
local treecats = {}
local catdata = {}
table.sort(cats,function(a,b) return a.order < b.order end)
local rootit = projtree:AddRoot("")
catdata[rootit:GetValue()] = {category = "root", children = treecats}
for i=1,#cats do
local it = projtree:AppendItem(rootit,cats[i].title)
treecats[i] = it
local c = cats[i]
local children = {}
catdata[it:GetValue()] = {category = c,children = children}
for i=1,#c.entry do
local e = c.entry[i]
local it = projtree:AppendItem(it,e.title)
catdata[it:GetValue()] = {page = e}
children[i] = it
end
projtree:Expand(it)
end
projtree:Expand(rootit)
local preferencesContent
projtree:Connect( wx.wxEVT_COMMAND_TREE_SEL_CHANGED,
function( event )
local item_id = event:GetItem():GetValue()
local data = catdata[item_id]
if data.category then
if data.children[1] then
projtree:SelectItem(data.children[1])
end
else
if preferencesContent then
preferencesPage:RemoveChild(preferencesContent)
end
preferencesContent = wx.wxPanel(preferencesPage,wx.wxID_ANY)
showpage(preferencesContent,data.page)
end
end )
local topsizer = wx.wxBoxSizer(wx.wxVERTICAL)
topsizer:Add(panel,0,wx.wxALL + wx.wxALIGN_CENTER,10)
topsizer:Add(wx.wxStaticLine(dialog, wx.wxID_ANY), 0, wx.wxEXPAND + wx.wxLEFT + wx.wxRIGHT, 10)
topsizer:Add(panel_buttons, 0, wx.wxALL + wx.wxALIGN_RIGHT, 10)
local buttonpanelsizer = wx.wxBoxSizer(wx.wxHORIZONTAL)
buttonpanelsizer:Add(btn_cancel,0,wx.wxALL + wx.wxALIGN_RIGHT,0)
buttonpanelsizer:AddSpacer(5)
buttonpanelsizer:Add(btn_apply,0,wx.wxALL + wx.wxALIGN_RIGHT,0)
buttonpanelsizer:AddSpacer(5)
buttonpanelsizer:Add(btn_ok,0,wx.wxALL + wx.wxALIGN_RIGHT,0)
panel_buttons:SetSizer(buttonpanelsizer)
buttonpanelsizer:Fit(panel_buttons)
local dialog = wx.wxDialog(ide.frame, ID "view.preferences.dialog","Preferences")
dialog:SetAutoLayout(true)
dialog:SetSizer(topsizer)
topsizer:Fit(dialog)
dialog:Center()
dialog:ShowModal()
local id_btn_ok = ID "view.preferences.dialog.button.ok"
local id_btn_cancel = ID "view.preferences.dialog.button.cancel"
local id_btn_apply = ID "view.preferences.dialog.button.apply"
local panel_buttons = wx.wxPanel(dialog,ID "view.preferences.dialog.buttonpanel")
local btn_ok = wx.wxButton(panel_buttons,id_btn_ok, "OK")
local btn_cancel = wx.wxButton(panel_buttons,id_btn_cancel, "Cancel")
local btn_apply = wx.wxButton(panel_buttons,id_btn_apply, "Apply")
dialog:Connect(id_btn_cancel, wx.wxEVT_COMMAND_BUTTON_CLICKED,
function (event)
dialog:EndModal(0)
end)
dialog:Connect(id_btn_ok, wx.wxEVT_COMMAND_BUTTON_CLICKED,
function (event)
dialog:EndModal(0)
end)
local panel = wx.wxPanel(dialog,ID "view.preferences.dialog.panel",
wx.wxDefaultPosition, wx.wxSize(600,400))
local projtree = wx.wxTreeCtrl(panel, ID "view.preferences.dialog.panel.tree",
wx.wxDefaultPosition, wx.wxSize(180,400),
wx.wxTR_HAS_BUTTONS + wx.wxTR_SINGLE + wx.wxTR_HIDE_ROOT)
local preferencesPage = wx.wxPanel(panel,ID "view.preferences.dialog.page",
wx.wxDefaultPosition, wx.wxSize(500,400))
local panelsizer = wx.wxBoxSizer(wx.wxHORIZONTAL)
panelsizer:Add(projtree,0,wx.wxALL + wx.wxALIGN_LEFT + wx.wxTOP + wx.wxBOTTOM,0)
panelsizer:AddSpacer(5)
panelsizer:Add(preferencesPage)
panel:SetSizer(panelsizer)
local treecats = {}
local catdata = {}
table.sort(cats,function(a,b) return a.order < b.order end)
local rootit = projtree:AddRoot("")
catdata[rootit:GetValue()] = {category = "root", children = treecats}
for i=1,#cats do
local it = projtree:AppendItem(rootit,cats[i].title)
treecats[i] = it
local c = cats[i]
local children = {}
catdata[it:GetValue()] = {category = c,children = children}
for i=1,#c.entry do
local e = c.entry[i]
local it = projtree:AppendItem(it,e.title)
catdata[it:GetValue()] = {page = e}
children[i] = it
end
projtree:Expand(it)
end
projtree:Expand(rootit)
local preferencesContent
projtree:Connect( wx.wxEVT_COMMAND_TREE_SEL_CHANGED,
function( event )
local item_id = event:GetItem():GetValue()
local data = catdata[item_id]
if data.category then
if data.children[1] then
projtree:SelectItem(data.children[1])
end
else
if preferencesContent then
preferencesPage:RemoveChild(preferencesContent)
end
preferencesContent = wx.wxPanel(preferencesPage,wx.wxID_ANY)
showpage(preferencesContent,data.page)
end
end )
local topsizer = wx.wxBoxSizer(wx.wxVERTICAL)
topsizer:Add(panel,0,wx.wxALL + wx.wxALIGN_CENTER,10)
topsizer:Add(wx.wxStaticLine(dialog, wx.wxID_ANY), 0, wx.wxEXPAND + wx.wxLEFT + wx.wxRIGHT, 10)
topsizer:Add(panel_buttons, 0, wx.wxALL + wx.wxALIGN_RIGHT, 10)
local buttonpanelsizer = wx.wxBoxSizer(wx.wxHORIZONTAL)
buttonpanelsizer:Add(btn_cancel,0,wx.wxALL + wx.wxALIGN_RIGHT,0)
buttonpanelsizer:AddSpacer(5)
buttonpanelsizer:Add(btn_apply,0,wx.wxALL + wx.wxALIGN_RIGHT,0)
buttonpanelsizer:AddSpacer(5)
buttonpanelsizer:Add(btn_ok,0,wx.wxALL + wx.wxALIGN_RIGHT,0)
panel_buttons:SetSizer(buttonpanelsizer)
buttonpanelsizer:Fit(panel_buttons)
dialog:SetAutoLayout(true)
dialog:SetSizer(topsizer)
topsizer:Fit(dialog)
dialog:Center()
dialog:ShowModal()
end

View File

@@ -1,318 +1,436 @@
-- authors: Lomtik Software (J. Winwood & John Labenski)
-- Luxinia Dev (Eike Decker & Christoph Kubisch)
---------------------------------------------------------
local ide = ide
-- ----------------------------------------------------------------------------
-- Initialize the wxConfig for loading/saving the preferences
local settings = wx.wxFileConfig(GetIDEString("settingsapp"),GetIDEString("settingsvendor"))
ide.settings = settings
if settings then
-- we dont like defaults ?
--settings:SetRecordDefaults()
end
local function settingsReadSafe(settings,what,default)
local cr,out = settings:Read(what,default)
if (cr) then
return out
else
return default
end
end
-- ----------------------------------------------------------------------------
-- wxConfig load/save preferences functions
function SettingsRestoreFramePosition(window, windowName)
local path = settings:GetPath()
settings:SetPath("/"..windowName)
local s = -1
s = tonumber(select(2,settings:Read("s", -1)))
local x = tonumber(select(2,settings:Read("x", 0)))
local y = tonumber(select(2,settings:Read("y", 0)))
local w = tonumber(select(2,settings:Read("w", 600)))
local h = tonumber(select(2,settings:Read("h", 400)))
if (s ~= 1) and (s ~= 2) then
local clientX, clientY, clientWidth, clientHeight
clientX, clientY, clientWidth, clientHeight = wx.wxClientDisplayRect()
if x < clientX then x = clientX end
if y < clientY then y = clientY end
if w > clientWidth then w = clientWidth end
if h > clientHeight then h = clientHeight end
window:SetSize(x, y, w, h)
elseif s == 1 then
window:Maximize(true)
end
settings:SetPath(path)
end
function SettingsSaveFramePosition(window, windowName)
local path = settings:GetPath()
settings:SetPath("/"..windowName)
local s = 0
local w, h = window:GetSizeWH()
local x, y = window:GetPositionXY()
if window:IsMaximized() then
s = 1
elseif window:IsIconized() then
s = 2
end
settings:Write("s", s==2 and 0 or s) -- iconized maybe - but that shouldnt be saved
if s == 0 then
settings:Write("x", x)
settings:Write("y", y)
settings:Write("w", w)
settings:Write("h", h)
end
settings:SetPath(path)
end
---
-- (table) SettingsRestoreFileHistory (function)
-- restores a list of recently loaded documents from the settings table
-- a table is returned which contains tables each with a filename key, pointing to
-- the filename
function SettingsRestoreFileHistory(fntab)
local path = settings:GetPath()
local listname = "/filehistory"
settings:SetPath(listname)
local outtab = {}
local inlist = {}
for id=1,ide.config.filehistorylength do
local couldread, name = settings:Read(tostring(id), "")
if not couldread or name == "" then break end
if not inlist[name] then
inlist[name] = true
table.insert(outtab,{filename = name})
end
end
if fntab then fntab(outtab) end
settings:SetPath(path)
return outtab
end
function SettingsAppendFileToHistory (filename)
local listname = "/filehistory"
local oldlist = SettingsRestoreFileHistory(nil,listname)
-- if the file has been in the history before, remove it
for i=#oldlist,1,-1 do
if oldlist[i] == filename then table.remove(oldlist,i) end
end
table.insert(oldlist,1,{filename=filename})
-- remove all entries that are no longer needed
while #oldlist>ide.config.filehistorylength do table.remove(oldlist) end
local path = settings:GetPath()
settings:DeleteGroup(listname)
settings:SetPath(listname)
for i,doc in ipairs(oldlist) do
settings:Write(tostring(i), doc.filename)
end
UpdateFileHistoryUI(oldlist)
settings:SetPath(path)
end
---
-- () SettingsRestoreFileSession (function)
-- restores a list of opened files from the file settings
-- calls the given function with the restored table, a list
-- of tables containing tables like
-- {filename = "filename", cursorpos = <cursor position>}
function SettingsRestoreFileSession(fntab)
local listname = "/session"
local path = settings:GetPath()
settings:SetPath(listname)
local outtab = {}
local couldread = true
local id = 1
local name
while(couldread) do
couldread, name = settings:Read(tostring(id), "")
local fname,cursorpos = name:match("^(.+);(.-)$")
name = fname or name
cursorpos = tonumber(cursorpos or 0)
couldread = couldread and name ~= ""
if (couldread) then
table.insert(outtab,{filename = name, cursorpos = cursorpos})
id = id + 1
end
end
local index = settingsReadSafe(settings,"index",1)
if fntab then fntab(outtab,index) end
settings:SetPath(path)
return outtab
end
---
-- () SettingsSaveFileList (table opendocs)
-- saves the list of currently opened documents (passed in the opendocs table)
-- in the settings.
function SettingsSaveFileSession(opendocs,index)
local listname = "/session"
local path = settings:GetPath()
settings:DeleteGroup(listname)
settings:SetPath(listname)
for i,doc in ipairs(opendocs) do
settings:Write(tostring(i), doc.filename..";"..doc.cursorpos)
end
settings:Write("index",index)
settings:SetPath(path)
end
---
-- () SettingsRestoreProjectSession (function)
function SettingsRestoreProjectSession(fntab)
local listname = "/projectsession"
local path = settings:GetPath()
settings:SetPath(listname)
local outtab = {}
local couldread = true
local id = 1
local name
while(couldread) do
couldread, name = settings:Read(tostring(id), "")
couldread = couldread and name ~= ""
if (couldread) then
if (wx.wxDirExists(name)) then
table.insert(outtab,name)
end
id = id + 1
end
end
if fntab then fntab(outtab) end
settings:SetPath(path)
return outtab
end
---
-- () SettingsSaveProjectSession (table projdirs)
-- saves the list of currently active projects
-- in the settings.
function SettingsSaveProjectSession(projdirs)
local listname = "/projectsession"
local path = settings:GetPath()
settings:DeleteGroup(listname)
settings:SetPath(listname)
for i,dir in ipairs(projdirs) do
settings:Write(tostring(i), dir)
end
settings:SetPath(path)
end
-----------------------------------
function SettingsRestoreView()
local listname = "/view"
local path = settings:GetPath()
settings:SetPath(listname)
local frame = ide.frame
local vsplitter = frame.vsplitter
local sidenotebook = vsplitter.sidenotebook
local splitter = vsplitter.splitter
local treevis = tonumber(settingsReadSafe(settings,"filetreevis",1))
local outvis = tonumber(settingsReadSafe(settings,"outputvis",1))
ide.config.view.vsplitterpos = tonumber(settingsReadSafe(settings,"filetreewidth",ide.config.view.vsplitterpos))
ide.config.view.splitterheight = tonumber(settingsReadSafe(settings,"outputheight",ide.config.view.splitterheight))
local w, h = frame:GetClientSizeWH()
if (treevis > 0) then
vsplitter:SplitVertically(sidenotebook,splitter,ide.config.view.vsplitterpos)
else
vsplitter:Initialize(splitter)
end
if (outvis > 0) then
splitter:SplitHorizontally(splitter.notebook, splitter.bottomnotebook, h-ide.config.view.splitterheight)
else
splitter:Initialize(splitter.notebook)
end
frame.menuBar:Check(ID "view.filetree.show", treevis > 0)
frame.menuBar:Check(ID "view.output.show", outvis > 0)
settings:SetPath(path)
end
function SettingsSaveView()
local listname = "/view"
local path = settings:GetPath()
settings:DeleteGroup(listname)
settings:SetPath(listname)
local frame = ide.frame
local vsplitter = frame.vsplitter
local splitter = vsplitter.splitter
local w, h = frame:GetClientSizeWH()
settings:Write("filetreevis", vsplitter:IsSplit())
settings:Write("filetreewidth", vsplitter:IsSplit() and vsplitter:GetSashPosition() or ide.config.view.vsplitterpos)
settings:Write("outputvis", splitter:IsSplit())
settings:Write("outputheight", splitter:IsSplit() and (h-splitter:GetSashPosition()) or ide.config.view.splitterheight)
settings:SetPath(path)
end
function SettingsRestoreEditorSettings()
local listname = "/editor"
local path = settings:GetPath()
settings:SetPath(listname)
ide.config.interpreter = settingsReadSafe(settings,"interpreter",ide.config.interpreter)
SetInterpreter(ide.config.interpreter)
end
function SettingsSaveEditorSettings()
local listname = "/editor"
local path = settings:GetPath()
settings:DeleteGroup(listname)
settings:SetPath(listname)
settings:Write("interpreter", ide.config.interpreter)
settings:SetPath(path)
end
-- authors: Lomtik Software (J. Winwood & John Labenski)
-- Luxinia Dev (Eike Decker & Christoph Kubisch)
---------------------------------------------------------
local ide = ide
-- ----------------------------------------------------------------------------
-- Initialize the wxConfig for loading/saving the preferences
local settings = wx.wxFileConfig(GetIDEString("settingsapp"),GetIDEString("settingsvendor"))
ide.settings = settings
local function settingsReadSafe(settings,what,default)
local cr,out = settings:Read(what,default)
if (cr) then
return out
else
return default
end
end
-- ----------------------------------------------------------------------------
-- wxConfig load/save preferences functions
function SettingsRestoreFramePosition(window, windowName)
local path = settings:GetPath()
settings:SetPath("/"..windowName)
local s = -1
s = tonumber(select(2,settings:Read("s", -1)))
local x = tonumber(select(2,settings:Read("x", 0)))
local y = tonumber(select(2,settings:Read("y", 0)))
local w = tonumber(select(2,settings:Read("w", 1000)))
local h = tonumber(select(2,settings:Read("h", 700)))
if (s ~= -1) and (s ~= 1) and (s ~= 2) then
local clientX, clientY, clientWidth, clientHeight
clientX, clientY, clientWidth, clientHeight = wx.wxClientDisplayRect()
if x < clientX then x = clientX end
if y < clientY then y = clientY end
if w > clientWidth then w = clientWidth end
if h > clientHeight then h = clientHeight end
window:SetSize(x, y, w, h)
elseif s == 1 then
window:Maximize(true)
end
settings:SetPath(path)
end
function SettingsSaveFramePosition(window, windowName)
local path = settings:GetPath()
settings:SetPath("/"..windowName)
local s = 0
local w, h = window:GetSizeWH()
local x, y = window:GetPositionXY()
if window:IsMaximized() then
s = 1
elseif window:IsIconized() then
s = 2
end
settings:Write("s", s==2 and 0 or s) -- iconized maybe - but that shouldnt be saved
if s == 0 then
settings:Write("x", x)
settings:Write("y", y)
settings:Write("w", w)
settings:Write("h", h)
end
settings:SetPath(path)
end
---
-- (table) SettingsRestoreFileHistory (function)
-- restores a list of recently loaded documents from the settings table
-- a table is returned which contains tables each with a filename key, pointing to
-- the filename
function SettingsRestoreFileHistory(fntab)
local path = settings:GetPath()
local listname = "/filehistory"
settings:SetPath(listname)
local outtab = {}
local inlist = {}
for id=1,ide.config.filehistorylength do
local couldread, name = settings:Read(tostring(id), "")
if not couldread or name == "" then break end
if not inlist[name] then
inlist[name] = true
table.insert(outtab,{filename = name})
end
end
if fntab then fntab(outtab) end
settings:SetPath(path)
return outtab
end
function SettingsAppendFileToHistory (filename)
local listname = "/filehistory"
local oldlist = SettingsRestoreFileHistory(nil,listname)
-- if the file has been in the history before, remove it
for i=#oldlist,1,-1 do
if oldlist[i] == filename then table.remove(oldlist,i) end
end
table.insert(oldlist,1,{filename=filename})
-- remove all entries that are no longer needed
while #oldlist>ide.config.filehistorylength do table.remove(oldlist) end
local path = settings:GetPath()
settings:DeleteGroup(listname)
settings:SetPath(listname)
for i,doc in ipairs(oldlist) do
settings:Write(tostring(i), doc.filename)
end
UpdateFileHistoryUI(oldlist)
settings:SetPath(path)
end
---
-- () SettingsRestoreFileSession (function)
-- restores a list of opened files from the file settings
-- calls the given function with the restored table, a list
-- of tables containing tables like
-- {filename = "filename", cursorpos = <cursor position>}
function SettingsRestoreFileSession(fntab)
local listname = "/session"
local path = settings:GetPath()
settings:SetPath(listname)
local outtab = {}
local couldread = true
local id = 1
local name
while(couldread) do
couldread, name = settings:Read(tostring(id), "")
local fname,cursorpos = name:match("^(.+);(.-)$")
name = fname or name
cursorpos = tonumber(cursorpos or 0)
couldread = couldread and name ~= ""
if (couldread) then
table.insert(outtab,{filename = name, cursorpos = cursorpos})
id = id + 1
end
end
local index = settingsReadSafe(settings,"index",1)
if fntab then fntab(outtab,index) end
settings:SetPath(path)
return outtab
end
---
-- () SettingsSaveFileList (table opendocs)
-- saves the list of currently opened documents (passed in the opendocs table)
-- in the settings.
function SettingsSaveFileSession(opendocs,index)
local listname = "/session"
local path = settings:GetPath()
settings:DeleteGroup(listname)
settings:SetPath(listname)
for i,doc in ipairs(opendocs) do
settings:Write(tostring(i), doc.filename..";"..doc.cursorpos)
end
settings:Write("index",index)
settings:SetPath(path)
end
---
-- () SettingsRestoreProjectSession (function)
function SettingsRestoreProjectSession(fntab)
local listname = "/projectsession"
local path = settings:GetPath()
settings:SetPath(listname)
local outtab = {}
local couldread = true
local id = 1
local name
while(couldread) do
couldread, name = settings:Read(tostring(id), "")
couldread = couldread and name ~= ""
if (couldread) then
if (wx.wxDirExists(name)) then
table.insert(outtab,name)
end
id = id + 1
end
end
if fntab then fntab(outtab) end
settings:SetPath(path)
return outtab
end
---
-- () SettingsSaveProjectSession (table projdirs)
-- saves the list of currently active projects
-- in the settings.
function SettingsSaveProjectSession(projdirs)
local listname = "/projectsession"
local path = settings:GetPath()
settings:DeleteGroup(listname)
settings:SetPath(listname)
for i,dir in ipairs(projdirs) do
settings:Write(tostring(i), dir)
end
settings:SetPath(path)
end
-----------------------------------
local function saveNotebook(nb)
local cnt = nb:GetPageCount()
local function addTo(tab,key,value)
local out = tab[key] or {}
table.insert(out,value)
tab[key] = out
end
local pagesX = {}
local pagesY = {}
local str = "nblayout|"
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)
addTo(pagesY,y,id)
end
local function sortedPages(tab)
local t = {}
for i,v in pairs(tab) do
table.insert(t,i)
end
table.sort(t)
return t
end
sortedX = sortedPages(pagesX)
sortedY = sortedPages(pagesY)
-- for now only support "1D" splits and prefer
-- dimension which has more, anything else
-- requires a more complex algorithm, yet to do
local pagesUse
local sortedUse
local split
if ( #sortedX >= #sortedY) then
pagesUse = pagesX
sortedUse = sortedX
split = "<X>"
else
pagesUse = pagesY
sortedUse = sortedY
split = "<Y>"
end
for i,v in ipairs(sortedUse) do
local pages = pagesUse[v]
for n,id in ipairs(pages) do
str = str..id.."|"
end
str = str..split.."|"
end
return str
end
local function loadNotebook(nb,str,fnIdConvert)
str = str:match("nblayout|(.+)")
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}
end
-- remove them
for i=cnt,1,-1 do
nb:RemovePage(i-1)
end
-- readd them and perform splits
local direction
local splits = {
X = wx.wxRIGHT,
Y = wx.wxBOTTOM,
}
local t = 0
local newsel
local function finishPage(page)
if (page.index == sel) then
newsel = t
end
t = t + 1
end
for cmd in str:gmatch("([^|]+)") do
local instr = cmd:match("<(%w)>")
if (not instr) then
local id = fnIdConvert and fnIdConvert(cmd) or cmd
local page = currentpages[id]
if (page) then
nb:AddPage(page.page, page.text)
currentpages[id] = nil
if (direction) then
nb:Split(t, direction)
end
finishPage(page)
end
end
direction = instr and splits[instr]
end
-- add anything we forgot
for i,page in pairs(currentpages) do
nb:AddPage(page.page, page.text)
finishPage(page)
end
if (newsel) then
nb:SetSelection(newsel)
end
end
function SettingsRestoreView()
local listname = "/view"
local path = settings:GetPath()
settings:SetPath(listname)
local frame = ide.frame
local uimgr = frame.uimgr
local layoutcur = uimgr:SavePerspective()
local layout = settingsReadSafe(settings,"uimgrlayout",layoutcur)
if (layout ~= layoutcur) then
uimgr:LoadPerspective(layout)
uimgr:Update()
end
local layoutcur = saveNotebook(frame.notebook)
local layout = settingsReadSafe(settings,"nblayout",layoutcur)
if (layout ~= layoutcur) then
loadNotebook(ide.frame.notebook,layout)
local openDocuments = ide.openDocuments
local nb = frame.notebook
local cnt = nb:GetPageCount()
for i=0,cnt-1 do
openDocuments[nb:GetPage(i):GetId()].index = i
end
end
local layoutcur = saveNotebook(frame.bottomnotebook)
local layout = settingsReadSafe(settings,"nbbtmlayout",layoutcur)
if (layout ~= layoutcur) then
loadNotebook(ide.frame.bottomnotebook,layout,
function(name) return name:match("console") or name end)
end
settings:SetPath(path)
end
function SettingsSaveView()
local listname = "/view"
local path = settings:GetPath()
settings:DeleteGroup(listname)
settings:SetPath(listname)
local frame = ide.frame
local uimgr = frame.uimgr
settings:Write("uimgrlayout",uimgr:SavePerspective())
settings:Write("nblayout", saveNotebook(frame.notebook))
settings:Write("nbbtmlayout",saveNotebook(frame.bottomnotebook))
settings:SetPath(path)
end
function SettingsRestoreEditorSettings()
local listname = "/editor"
local path = settings:GetPath()
settings:SetPath(listname)
ide.config.interpreter = settingsReadSafe(settings,"interpreter",ide.config.interpreter)
ProjectSetInterpreter(ide.config.interpreter)
end
function SettingsSaveEditorSettings()
local listname = "/editor"
local path = settings:GetPath()
settings:DeleteGroup(listname)
settings:SetPath(listname)
settings:Write("interpreter", ide.interpreter and ide.interpreter.fname or "_undefined_")
settings:SetPath(path)
end

View File

@@ -1,195 +1,395 @@
-- authors: Luxinia Dev (Eike Decker & Christoph Kubisch)
---------------------------------------------------------
local ide = ide
--
-- shellbox - a lua testbed environment within estrela
--
local shellbox = ide.frame.vsplitter.splitter.bottomnotebook.shellbox
local out = shellbox.output
local code = shellbox.input
local remote = shellbox.remote
local remotesend
local remoteuid
local frame = ide.frame
out:SetFont(ide.ofont)
out:StyleSetFont(wxstc.wxSTC_STYLE_DEFAULT, ide.ofont)
out:StyleClearAll()
out:SetBufferedDraw(true)
out:WrapCount(80)
out:MarkerDefine(BREAKPOINT_MARKER, wxstc.wxSTC_MARK_BACKGROUND, wx.wxBLACK, wx.wxColour(255, 220, 220))
out:SetReadOnly(true)
StylesApplyToEditor(ide.config.stylesoutshell,out,ide.ofont,ide.ofontItalic)
local function shellPrint(...)
out:SetReadOnly(false)
local cnt = select('#',...)
for i=1,cnt do
local x = select(i,...)
out:InsertText(out:GetLength(),tostring(x)..(i < cnt and "\t" or ""))
end
out:InsertText(out:GetLength(),"\n")
out:GotoPos(out:GetLength())
out:SetReadOnly(true)
end
DisplayShell = shellPrint
DisplayShellErr = function (...)
out:MarkerAdd(out:GetLineCount()-1, BREAKPOINT_MARKER)
DisplayShell("! " .. ...)
end
local function createenv ()
local env = {}
setmetatable(env,{__index = _G})
local function luafilename(level)
level = level and level + 1 or 2
local src
while (true) do
src = debug.getinfo(level)
if (src == nil) then return nil,level end
if (string.byte(src.source) == string.byte("@")) then
return string.sub(src.source,2),level
end
level = level + 1
end
end
local function luafilepath(level)
local src,level = luafilename(level)
if (src == nil) then return src,level end
src = string.gsub(src,"[\\/][^\\//]*$","")
return src,level
end
local function relativeFilename(file)
assert(type(file)=='string',"String as filename expected")
local name = file
local level = 3
while (name) do
if (wx.wxFileName(name):FileExists()) then return name end
name,level = luafilepath(level)
if (name == nil) then break end
name = name .. "/" .. file
end
return file
end
local function relativeFilepath(file)
local name,level = luafilepath(3)
return (file and name) and name.."/"..file or file or name
end
local _loadfile = loadfile
local function loadfile(file)
assert(type(file)=='string',"String as filename expected")
local name = relativeFilename(file)
return _loadfile(name)
end
local function dofile(file, ...)
assert(type(file) == 'string',"String as filename expected")
local fn,err = loadfile(file)
local args = {...}
if not fn then
shellPrint("Error: "..err)
else
setfenv(fn,env)
xpcall(function() return fn(unpack(args)) end,function(err)
shellPrint(debug.traceback(err))
end)
end
end
env.print = shellPrint
env.dofile = dofile
env.loadfile = loadfile
env.RELFILE = relativeFilename
env.RELPATH = relativeFilepath
return env
end
local env = createenv()
code:SetBufferedDraw(true)
code:SetFont(ide.ofont)
code:StyleSetFont(wxstc.wxSTC_STYLE_DEFAULT, ide.ofont)
code:StyleClearAll()
code:SetTabWidth(4)
code:SetIndent(ide.config.editor.tabwidth or 4)
code:SetUseTabs(ide.config.editor.usetabs and true or false)
code:SetViewWhiteSpace(ide.config.editor.whitespace and true or false)
code:SetIndentationGuides(true)
--StylesApplyToEditor(ide.config.stylesoutshell,code,ide.ofont,ide.ofontItalic)
SetupKeywords(code,"lua",nil,ide.config.stylesoutshell,ide.ofont,ide.ofontItalic)
local accel = wx.wxAcceleratorTable{
{wx.wxACCEL_CTRL,13,ID "shellbox.execute"},
{wx.wxACCEL_CTRL+wx.wxACCEL_ALT,string.byte "\b",ID "shellbox.eraseall"}
}
code:SetAcceleratorTable(accel)
function ShellExecuteCode(ev,wfilename)
local fn,err
local tx
local marker = "> " -- local execution
if (wfilename) then
fn,err = loadfile(wfilename:GetFullPath())
elseif(remotesend and remote:IsChecked()) then
marker = ">> " -- remote execution
tx = code:GetText()
remotesend(tx)
else
tx = code:GetText()
-- return (...) works for everything except assignments
fn,err = loadstring("return (" .. tx .. ")")
if err then -- now try assignments
fn,err = loadstring(tx)
end
end
if (tx ~= nil) then
DisplayShell(marker .. tx)
end
if fn==nil and err then
DisplayShellErr(err)
elseif fn then
setfenv(fn,env)
local ok, res = pcall(fn)
if ok then DisplayShell(res)
else DisplayShellErr(res)
end
end
end
function ShellSupportRemote(client,uid)
remote:Enable(client and true or false)
remotesend = client
remoteuid = client and uid
if (not client) then
remote:SetValue(false)
end
end
shellbox:Connect(wxstc.wxEVT_STC_CHARADDED,
function (event)
frame:SetStatusText("Execute your code pressing CTRL+ENTER")
end)
frame:Connect(ID "shellbox.eraseall", wx.wxEVT_COMMAND_MENU_SELECTED, function()
code:SetText ""
end)
frame:Connect(ID "shellbox.execute", wx.wxEVT_COMMAND_MENU_SELECTED, ShellExecuteCode)
shellbox:Connect(ID "shellbox.run",wx.wxEVT_COMMAND_BUTTON_CLICKED, ShellExecuteCode)
shellbox:Connect(ID "shellbox.remote",wx.wxEVT_COMMAND_CHECKBOX_CLICKED, function(event)
if (remotesend) then
CommandLineToShell(remoteuid,event:IsChecked())
end
end)
-- authors: Luxinia Dev (Eike Decker & Christoph Kubisch)
---------------------------------------------------------
local ide = ide
--
-- shellbox - a lua testbed environment within the IDE
--
local bottomnotebook = ide.frame.bottomnotebook
local out = bottomnotebook.shellbox
local remotesend
local OUTPUT_MARKER = 3
local OUTPUT_MARKER_VALUE = 8 -- = 2^OUTPUT_MARKER
local frame = ide.frame
out:SetFont(ide.ofont)
out:StyleSetFont(wxstc.wxSTC_STYLE_DEFAULT, ide.ofont)
out:StyleClearAll()
out:SetBufferedDraw(true)
out:SetTabWidth(ide.config.editor.tabwidth or 2)
out:SetIndent(ide.config.editor.tabwidth or 2)
out:SetUseTabs(ide.config.editor.usetabs and true or false)
out:SetViewWhiteSpace(ide.config.editor.whitespace and true or false)
out:SetIndentationGuides(true)
out:SetWrapMode(wxstc.wxSTC_WRAP_WORD)
out:SetWrapStartIndent(0)
out:SetWrapVisualFlagsLocation(wxstc.wxSTC_WRAPVISUALFLAGLOC_END_BY_TEXT)
out:SetWrapVisualFlags(wxstc.wxSTC_WRAPVISUALFLAG_END)
out:MarkerDefine(CURRENT_LINE_MARKER, wxstc.wxSTC_MARK_CHARACTER+string.byte('>'), wx.wxBLACK, wx.wxColour(240, 240, 240))
out:MarkerDefine(BREAKPOINT_MARKER, wxstc.wxSTC_MARK_BACKGROUND, wx.wxBLACK, wx.wxColour(255, 220, 220))
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)
local function getPromptLine()
local totalLines = out:GetLineCount()
return out:MarkerPrevious(totalLines+1, CURRENT_LINE_MARKER_VALUE)
end
local function getPromptText()
local prompt = getPromptLine()
return out:GetTextRange(out:PositionFromLine(prompt), out:GetLength())
end
local function setPromptText(text)
local length = out:GetLength()
out:SetTargetStart(length - string.len(getPromptText()))
out:SetTargetEnd(length)
out:ReplaceTarget(text)
out:GotoPos(out:GetLength())
end
local function positionInLine(line)
return out:GetCurrentPos() - out:PositionFromLine(line)
end
local function caretOnPromptLine(disallowLeftmost)
local promptLine = getPromptLine()
local boundary = disallowLeftmost and 0 or -1
return (out:GetCurrentLine() > promptLine
or out:GetCurrentLine() == promptLine and positionInLine(promptLine) > boundary)
end
local function chomp(line)
return line:gsub("%s+$", "")
end
local function getInput(line)
local nextMarker = line
repeat
nextMarker = nextMarker+1
until out:MarkerGet(nextMarker) > 0 -- check until we find at least some marker
return chomp(out:GetTextRange(out:PositionFromLine(line),
out:PositionFromLine(nextMarker)))
end
local currentHistory
local function getNextHistoryLine(forward, promptText)
local count = out:GetLineCount()
if currentHistory == nil then currentHistory = count end
if forward then
currentHistory = out:MarkerNext(currentHistory+1, CURRENT_LINE_MARKER_VALUE)
if currentHistory == -1 then
currentHistory = count
return ""
end
else
currentHistory = out:MarkerPrevious(currentHistory-1, CURRENT_LINE_MARKER_VALUE)
if currentHistory == -1 then
currentHistory = -1
return ""
end
end
-- need to skip the current prompt line
-- or skip repeated commands
if currentHistory == getPromptLine()
or getInput(currentHistory) == promptText then
return getNextHistoryLine(forward, promptText)
end
return getInput(currentHistory)
end
local function shellPrint(marker, ...)
local cnt = select('#',...)
local isPrompt = marker and (getPromptLine() > -1)
local text = ''
for i=1,cnt do
local x = select(i,...)
text = text .. tostring(x)..(i < cnt and "\t" or "")
end
-- add "\n" if it is missing
if text then text = text:gsub("\n$", "") .. "\n" end
local lines = out:GetLineCount()
local promptLine = isPrompt and getPromptLine() or nil
local insertLineAt = isPrompt and getPromptLine() or out:GetLineCount()-1
local insertAt = isPrompt and out:PositionFromLine(getPromptLine()) or out:GetLength()
out:InsertText(insertAt, text)
local linesAdded = out:GetLineCount() - lines
if marker then
if promptLine then out:MarkerDelete(promptLine, CURRENT_LINE_MARKER) end
for line = insertLineAt, insertLineAt + linesAdded - 1 do
out:MarkerAdd(line, marker)
end
if promptLine then out:MarkerAdd(promptLine+linesAdded, CURRENT_LINE_MARKER) end
end
out:EmptyUndoBuffer() -- don't allow the user to undo shell text
out:GotoPos(out:GetLength())
out:EnsureVisibleEnforcePolicy(out:GetLineCount()-1)
end
DisplayShell = function (...)
shellPrint(OUTPUT_MARKER, ...)
end
DisplayShellErr = function (...)
shellPrint(BREAKPOINT_MARKER, ...)
end
DisplayShellDirect = function (...)
shellPrint(nil, ...)
end
DisplayShellPrompt = function (...)
-- don't print anything; just mark the line with a prompt mark
out:MarkerAdd(out:GetLineCount()-1, CURRENT_LINE_MARKER)
end
local function filterTraceError(err, addedret)
local err = err:match("(.-:%d+:.-)\n[^\n]*\n[^\n]*\n[^\n]*src/editor/shellbox.lua:.*in function 'executeShellCode'")
err = err:gsub("stack traceback:.-\n[^\n]+\n?","")
if addedret then err = err:gsub('^%[string "return ', '[string "') end
err = err:match("(.*)\n[^\n]*%(tail call%): %?$") or err
return err
end
local function createenv ()
local env = {}
setmetatable(env,{__index = _G})
local function luafilename(level)
level = level and level + 1 or 2
local src
while (true) do
src = debug.getinfo(level)
if (src == nil) then return nil,level end
if (string.byte(src.source) == string.byte("@")) then
return string.sub(src.source,2),level
end
level = level + 1
end
end
local function luafilepath(level)
local src,level = luafilename(level)
if (src == nil) then return src,level end
src = string.gsub(src,"[\\/][^\\//]*$","")
return src,level
end
local function relativeFilename(file)
assert(type(file)=='string',"String as filename expected")
local name = file
local level = 3
while (name) do
if (wx.wxFileName(name):FileExists()) then return name end
name,level = luafilepath(level)
if (name == nil) then break end
name = name .. "/" .. file
end
return file
end
local function relativeFilepath(file)
local name,level = luafilepath(3)
return (file and name) and name.."/"..file or file or name
end
local _loadfile = loadfile
local function loadfile(file)
assert(type(file)=='string',"String as filename expected")
local name = relativeFilename(file)
return _loadfile(name)
end
local function dofile(file, ...)
assert(type(file) == 'string',"String as filename expected")
local fn,err = loadfile(file)
local args = {...}
if not fn then
DisplayShellErr(err)
else
setfenv(fn,env)
return fn(unpack(args))
end
end
env.print = DisplayShell
env.dofile = dofile
env.loadfile = loadfile
env.RELFILE = relativeFilename
env.RELPATH = relativeFilepath
return env
end
local env = createenv()
local function executeShellCode(tx)
if tx == nil or tx == '' then return end
DisplayShellPrompt('')
local addedret = false
local fn,err
if remotesend then
remotesend(tx)
else
fn,err = loadstring(tx)
-- for statement queries create the return
if err and (err:find("'=' expected near '<eof>'") or
err:find("unexpected symbol near '")) then
local errmore
fn,errmore = loadstring("return "..tx:gsub("^%s*=%s*",""))
addedret = not errmore
end
end
if fn == nil and err then
DisplayShellErr(err)
elseif fn then
setfenv(fn,env)
-- set the project dir as the current dir to allow "require" calls
-- to work from shell
local projectDir, cwd = FileTreeGetDir()
if projectDir then
cwd = wx.wxFileName.GetCwd()
wx.wxFileName.SetCwd(projectDir)
end
local ok, res = xpcall(fn,
function(err)
DisplayShellErr(filterTraceError(debug.traceback(err), addedret))
end)
-- restore the current dir
if projectDir then wx.wxFileName.SetCwd(cwd) end
if ok and (addedret or res ~= nil) then DisplayShell(res) end
end
end
function ShellSupportRemote(client,uid)
remotesend = client
local index = bottomnotebook:GetPageIndex(out)
if index then
bottomnotebook:SetPageText(index,
client and "Remote console" or "Local console")
end
end
function ShellExecuteFile(wfilename)
if (not wfilename) then return end
local cmd = 'dofile([['..wfilename:GetFullPath()..']])'
ShellExecuteCode(cmd)
end
function ShellExecuteCode(code)
local index = bottomnotebook:GetPageIndex(bottomnotebook.shellbox)
if ide.config.activateoutput and bottomnotebook:GetSelection() ~= index then
bottomnotebook:SetSelection(index)
end
DisplayShellDirect(code)
executeShellCode(code)
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.]])
DisplayShellPrompt('')
end
out:Connect(wx.wxEVT_KEY_DOWN,
function (event)
-- this loop is only needed to allow to get to the end of function easily
-- "return" aborts the processing and ignores the key
-- "break" aborts the processing and processes the key normally
while true do
local key = event:GetKeyCode()
if key == wx.WXK_UP or key == wx.WXK_NUMPAD_UP then
-- if we are below the prompt line, then allow to go up
-- through multiline entry
if out:GetCurrentLine() > getPromptLine() then break end
-- if we are not on the caret line, then don't move
if not caretOnPromptLine() then return end
local promptText = getPromptText()
setPromptText(getNextHistoryLine(false, promptText))
return
elseif key == wx.WXK_DOWN or key == wx.WXK_NUMPAD_DOWN then
-- if we are above the last line, then allow to go down
-- through multiline entry
local totalLines = out:GetLineCount()-1
if out:GetCurrentLine() < totalLines then break end
if not caretOnPromptLine() then break end
local promptText = getPromptText()
setPromptText(getNextHistoryLine(true, promptText))
return
elseif key == wx.WXK_LEFT or key == wx.WXK_NUMPAD_LEFT then
if not caretOnPromptLine(true) then return end
elseif key == wx.WXK_BACK then
if not caretOnPromptLine(true) then return end
elseif key == wx.WXK_DELETE or key == wx.WXK_NUMPAD_DELETE then
if not caretOnPromptLine()
or out:LineFromPosition(out:GetSelectionStart()) < getPromptLine() then
return
end
elseif key == wx.WXK_PAGEUP or key == wx.WXK_NUMPAD_PAGEUP
or key == wx.WXK_PAGEDOWN or key == wx.WXK_NUMPAD_PAGEDOWN
or key == wx.WXK_END or key == wx.WXK_NUMPAD_END
or key == wx.WXK_HOME or key == wx.WXK_NUMPAD_HOME
or key == wx.WXK_RIGHT or key == wx.WXK_NUMPAD_RIGHT
or key == wx.WXK_SHIFT or key == wx.WXK_CONTROL
or key == wx.WXK_ALT then
break
elseif key == wx.WXK_RETURN or key == WXK_NUMPAD_ENTER then
if not caretOnPromptLine()
or out:LineFromPosition(out:GetSelectionStart()) < getPromptLine() then
return
end
-- allow multiline entry for shift+enter
if caretOnPromptLine(true) and event:ShiftDown() then break end
local promptText = getPromptText()
if promptText == 'clear' then
out:ClearAll()
displayShellIntro()
else
DisplayShellDirect('\n')
executeShellCode(promptText)
end
currentHistory = getPromptLine() -- reset history
return -- don't need to do anything else with return
else
-- move cursor to end if not already there
if not caretOnPromptLine() then
out:GotoPos(out:GetLength())
-- check if the selection starts before the prompt line and reset it
elseif out:LineFromPosition(out:GetSelectionStart()) < getPromptLine() then
out:GotoPos(out:GetLength())
out:SetSelection(out:GetSelectionEnd()+1,out:GetSelectionEnd())
end
end
break
end
event:Skip()
end)
displayShellIntro()

View File

@@ -1,101 +1,100 @@
-- authors: Luxinia Dev (Eike Decker & Christoph Kubisch)
---------------------------------------------------------
local ide = ide
--[[ single instance
open an UDP port - if it fails it is either because
- Estrela is running already
- an application is already blocking that port
if it fails it tries to contact the running application
- if it confirms being the estrela IDE we let that instance open it, finish our application
- otherwise we throw an error message on the user and start like normal
probably a pitfal: an estreala instance is running but is not visible (because it was finished
though the UDP thing still runs)
]]
if not ide.config.singleinstance then return end
require "socket"
local port = ide.config.singleinstanceport
local svr = socket.udp()
local success, errmsg = svr:setsockname("127.0.0.1",port) -- bind on local host
local protocoll = {client = {}, server = {}}
protocoll.client.greeting = "Is this you, Estrela? It's me, a new instance."
protocoll.server.greeting = "Yes it is me, how may I serve you?"
protocoll.client.requestloading = "Could you please load this file for me: %s"
protocoll.server.answerok = "Sure. You may now leave."
if success then -- ok, server was started, we are solo
--TODO: if multiple files are to be opened, each file is handled one by one - we could create a single string instead...
ide.idletimer = wx.wxTimer(wx.wxGetApp())
ide.idletimer:Start(200,false)
svr:settimeout(0) -- don't block
wx.wxGetApp():Connect(wx.wxEVT_TIMER,function (evt)
if ide.exitingProgram then -- if exiting, terminate the timer loop
wx.wxGetApp():Disconnect(wx.wxEVT_TIMER)
return
end
local msg, err, port = svr:receivefrom() -- receive a msg
if msg then
local ip = err -- the errmsg is actually the IP
-- DisplayOutput("client sent request: "..tostring(ip)..","..tostring(port).."\n")
-- DisplayOutput("UDP.SingleInstanceServer: "..msg.."\n")
if msg == protocoll.client.greeting then -- just send back hi
svr:sendto(protocoll.server.greeting,ip,port)
elseif msg:match(protocoll.client.requestloading:gsub("%%s",".+$")) then -- ok we need to open something
local filename = msg:match(protocoll.client.requestloading:gsub("%%s","(.+)$"))
-- DisplayOutput("UDP.SingleInstanceServer: open file "..filename.."\n")
LoadFile(filename, nil, true)
svr:sendto(protocoll.server.answerok,ip,port)
ide.frame:RequestUserAttention() -- let's let the user know we want his attention
end
end
--DisplayOutput("check "..os.clock().."\n")
end)
else -- something different is running on our port
local cln = socket.udp()
cln:setpeername("127.0.0.1",port)
cln:settimeout(5) -- two seconds of waiting should be enough, if no response, we asume we are running
cln:send(protocoll.client.greeting)
local msg,err = cln:receive()
local arg = ide.arg
if msg and msg == protocoll.server.greeting then
local failed = false
for index = 2, #arg do
local fileName = arg[index]
if fileName ~= "--" then
cln:send(protocoll.client.requestloading:format(fileName))
local msg,err = cln:receive()
if msg~=protocoll.server.answerok then
failed = true
print(err,msg)
else
end
end
end
if failed then
print("The server instance failed to open the files, this instance will continue running.")
else -- done
os.exit(0)
end
--DisplayOutput("OK\n")
else
print("The Single instance communication has failed, it is not certain if this is the only running instance")
end
end
--print("UDP Server: "..success.." - "..tostring(errmsg).."\n")
-- authors: Luxinia Dev (Eike Decker & Christoph Kubisch)
---------------------------------------------------------
local ide = ide
--[[ single instance
open an UDP port - if it fails it is either because
- IDE is running already
- an application is already blocking that port
if it fails it tries to contact the running application
- if it confirms being the IDE we let that instance open it, finish our application
- otherwise we throw an error message on the user and start like normal
probably a pitfal: an estreala instance is running but is not visible (because it was finished
though the UDP thing still runs)
]]
if not ide.config.singleinstance then return end
require "socket"
local port = ide.config.singleinstanceport
local svr = socket.udp()
local success, errmsg = svr:setsockname("127.0.0.1",port) -- bind on local host
local protocoll = {client = {}, server = {}}
protocoll.client.greeting = "Is this you, my IDE? It's me, a new instance."
protocoll.server.greeting = "Yes it is me, how may I serve you?"
protocoll.client.requestloading = "Could you please load this file for me: %s"
protocoll.server.answerok = "Sure. You may now leave."
if success then -- ok, server was started, we are solo
--TODO: if multiple files are to be opened, each file is handled one by one - we could create a single string instead...
ide.idletimer = wx.wxTimer(wx.wxGetApp())
ide.idletimer:Start(200,false)
svr:settimeout(0) -- don't block
wx.wxGetApp():Connect(wx.wxEVT_TIMER,function (evt)
if ide.exitingProgram then -- if exiting, terminate the timer loop
wx.wxGetApp():Disconnect(wx.wxEVT_TIMER)
return
end
local msg, err, port = svr:receivefrom() -- receive a msg
if msg then
local ip = err -- the errmsg is actually the IP
-- DisplayOutput("client sent request: "..tostring(ip)..","..tostring(port).."\n")
-- DisplayOutput("UDP.SingleInstanceServer: "..msg.."\n")
if msg == protocoll.client.greeting then -- just send back hi
svr:sendto(protocoll.server.greeting,ip,port)
elseif msg:match(protocoll.client.requestloading:gsub("%%s",".+$")) then -- ok we need to open something
local filename = msg:match(protocoll.client.requestloading:gsub("%%s","(.+)$"))
-- DisplayOutput("UDP.SingleInstanceServer: open file "..filename.."\n")
LoadFile(filename, nil, true)
svr:sendto(protocoll.server.answerok,ip,port)
ide.frame:RequestUserAttention() -- let's let the user know we want his attention
end
end
--DisplayOutput("check "..os.clock().."\n")
end)
else -- something different is running on our port
local cln = socket.udp()
cln:setpeername("127.0.0.1",port)
cln:settimeout(5) -- two seconds of waiting should be enough, if no response, we asume we are running
cln:send(protocoll.client.greeting)
local msg,err = cln:receive()
local arg = ide.arg
if msg and msg == protocoll.server.greeting then
local failed = false
for index = 2, #arg do
local fileName = arg[index]
if fileName ~= "--" then
cln:send(protocoll.client.requestloading:format(fileName))
local msg,err = cln:receive()
if msg~=protocoll.server.answerok then
failed = true
print(err,msg)
else
end
end
end
if failed then
print("The server instance failed to open the files, this instance will continue running.")
else -- done
os.exit(0)
end
--DisplayOutput("OK\n")
else
print("The Single instance communication has failed, it is not certain if this is the only running instance")
end
end
--print("UDP Server: "..success.." - "..tostring(errmsg).."\n")

View File

@@ -1,301 +1,317 @@
-- authors: Luxinia Dev (Eike Decker & Christoph Kubisch)
---------------------------------------------------------
local ide = ide
----------
-- Style
--
-- common style attributes
-- ---------------------------
-- fg foreground - {r,g,b} 0-255
-- bg background - {r,g,b} 0-255
-- u underline - boolean
-- b bold - boolean
-- i italic - boolean
-- fill fill to end - boolean
function StylesGetDefault()
return {
-- lexer specific (inherit fg/bg from text)
lexerdef = {fg = {128, 128, 128},},
comment = {fg = {0, 127, 0 },bg = {240, 240, 220}, fill= true,},
stringtxt = {fg = {127, 0, 127},},
stringeol = {fg = {0, 0, 0 },bg = {224, 192, 224}, fill = true, b = true},
preprocessor = {fg = {127, 127, 0 },},
operator = {fg = {0, 0, 0 },},
number = {fg = {90, 100, 0 },},
keywords0 = {fg = {0, 0, 127}, b = true,},
keywords1 = {fg = {127, 0, 0},},
keywords2 = {fg = {0, 127, 0},},
keywords3 = {fg = {0, 0, 127},},
keywords4 = {fg = {127, 0, 95},},
keywords5 = {fg = {35, 95, 175},},
keywords6 = {fg = {0, 127, 127},},
keywords7 = {fg = {240, 255, 255},},
-- common (inherit fg/bg from text)
text = nil, -- let os pick
linenumber = {fg = {192, 192, 192},},
bracematch = {fg = {0, 0, 255}, b = true},
bracemiss = {fg = {255, 0, 0 }, b = true},
escapechar = nil,
indent = {fg = {192, 192, 192},bg = {255, 255, 255},},
calltip = nil,
-- common special (need custom fg & bg )
calltipbg = nil,
sel = nil,
caret = nil,
caretlinebg = nil,
fold = nil,
whitespace = {fg = {180, 180, 180},},
-- indicators
fncall = {fg = {175,175,255}, st= wxstc.wxSTC_INDIC_BOX},
}
end
-- used to fill unset bg colors
local defaultfg = nil
local defaultbg = nil
local function applymarker(editor,marker,clrfg,clrbg)
if (clrfg) then
editor:MarkerSetForeground(marker,clrfg)
end
if (clrbg) then
editor:MarkerSetBackground(marker,clrbg)
end
end
local specialmapping = {
sel = function(editor,style)
if (style.fg) then
editor:SetSelForeground(1,wx.wxColour(unpack(style.fg)))
else
editor:SetSelForeground(0)
end
if (style.bg) then
editor:SetSelBackground(1,wx.wxColour(unpack(style.bg)))
else
editor:SetSelBackground(0)
end
end,
caret = function(editor,style)
if (style.fg) then
editor:SetCaretForeground(wx.wxColour(unpack(style.fg)))
end
--if (style.bg) then
-- editor:SetCaretBackground(wx.wxColour(unpack(style.bg)))
--end
end,
caretlinebg = function(editor,style)
if (style.bg) then
editor:SetCaretLineBackground(wx.wxColour(unpack(style.bg)))
end
end,
whitespace = function(editor,style)
if (style.fg) then
editor:SetWhitespaceForeground(1,wx.wxColour(unpack(style.fg)))
else
--editor:SetWhitespaceForeground(0)
end
if (style.bg) then
editor:SetWhitespaceBackground(1,wx.wxColour(unpack(style.bg)))
else
--editor:SetWhitespaceBackground(0)
end
end,
calltipbg = function(editor,style)
if (style.bg) then
editor:CallTipSetBackground(wx.wxColour(unpack(style.bg)))
end
end,
fold = function(editor,style)
local clrfg = style.fg and wx.wxColour(unpack(style.fg))
local clrbg = style.bg and wx.wxColour(unpack(style.bg))
if (clrfg or clrbg) then
applymarker(editor,wxstc.wxSTC_MARKNUM_FOLDEROPEN, clrfg,clrbg)
applymarker(editor,wxstc.wxSTC_MARKNUM_FOLDER, clrfg,clrbg)
applymarker(editor,wxstc.wxSTC_MARKNUM_FOLDERSUB, clrfg,clrbg)
applymarker(editor,wxstc.wxSTC_MARKNUM_FOLDERTAIL, clrfg,clrbg)
applymarker(editor,wxstc.wxSTC_MARKNUM_FOLDEREND, clrfg,clrbg)
applymarker(editor,wxstc.wxSTC_MARKNUM_FOLDEROPENMID, clrfg,clrbg)
applymarker(editor,wxstc.wxSTC_MARKNUM_FOLDERMIDTAIL, clrfg,clrbg)
end
end,
}
local defaultmapping = {
text = wxstc.wxSTC_STYLE_DEFAULT,
linenumber = wxstc.wxSTC_STYLE_LINENUMBER,
bracematch = wxstc.wxSTC_STYLE_BRACELIGHT,
bracemiss = wxstc.wxSTC_STYLE_BRACEBAD,
escapechar = wxstc.wxSTC_STYLE_CONTROLCHAR,
indent = wxstc.wxSTC_STYLE_INDENTGUIDE,
calltip = wxstc.wxSTC_STYLE_CALLTIP,
}
function StylesApplyToEditor(styles,editor,font,fontitalic,lexerconvert)
local function applystyle(style,id)
editor:StyleSetFont(id, style.i and fontitalic or font)
editor:StyleSetBold(id, style.b or false)
editor:StyleSetUnderline(id, style.u or false)
editor:StyleSetEOLFilled(id, style.fill or false)
if (style.fg or defaultfg) then
editor:StyleSetForeground(id, style.fg and wx.wxColour(unpack(style.fg)) or defaultfg)
end
if (style.bg or defaultbg) then
editor:StyleSetBackground(id, style.bg and wx.wxColour(unpack(style.bg)) or defaultbg)
end
end
editor:StyleResetDefault()
editor:SetFont(font)
if (styles.text) then
applystyle(styles.text,defaultmapping["text"])
else
applystyle({},defaultmapping["text"])
end
editor:StyleClearAll()
defaultfg = styles.text and styles.text.fg and wx.wxColour(unpack(styles.text.fg)) or nil
defaultbg = styles.text and styles.text.bg and wx.wxColour(unpack(styles.text.bg)) or nil
for name,style in pairs(styles) do
if (specialmapping[name]) then
specialmapping[name](editor,style)
elseif (defaultmapping[name]) then
applystyle(style,defaultmapping[name])
end
if (lexerconvert and lexerconvert[name]) then
local targets = lexerconvert[name]
for n,outid in pairs(targets) do
applystyle(style,outid)
end
end
end
do
editor:IndicatorSetStyle(0,styles.fncall and styles.fncall.st or wxstc.wxSTC_INDIC_BOX)
editor:IndicatorSetForeground(0,wx.wxColour(unpack(styles.fncall and styles.fncall.fg or {128,128,128})))
end
editor:Colourise(0, -1)
end
function ReApplySpecAndStyles()
local openDocuments = ide.openDocuments
for i,doc in pairs(openDocuments) do
if (doc.editor.spec) then
SetupKeywords(doc.editor,nil,doc.editor.spec)
end
end
local errorlog = ide.frame.vsplitter.splitter.bottomnotebook.errorlog
local shellbox = ide.frame.vsplitter.splitter.bottomnotebook.shellbox
SetupKeywords(shellbox.input,"lua",nil,ide.config.stylesoutshell,ide.ofont,ide.ofontItalic)
StylesApplyToEditor(ide.config.stylesoutshell,errorlog,ide.ofont,ide.ofontItalic)
StylesApplyToEditor(ide.config.stylesoutshell,shellbox.output,ide.ofont,ide.ofontItalic)
end
function LoadConfigStyle()
local fileDialog = wx.wxFileDialog(ide.frame, "Open Config File",
"/cfg",
"",
"Lua file (*.lua)|*.lua|All files (*)|*",
wx.wxOPEN + wx.wxFILE_MUST_EXIST)
if fileDialog:ShowModal() == wx.wxID_OK then
local cfg = {path = {}, editor = {}, view ={}, acandtip = {}, outputshell = {},}
local cfgfn,err = loadfile(fileDialog:GetPath())
if cfgfn then
setfenv(cfgfn,cfg)
cfgfn = xpcall(cfgfn,function(err)DisplayOutput("Error while executing configuration file: \n",debug.traceback(err))end)
end
if not (cfgfn and (cfg.styles or cfg.stylesoutshell)) then
wx.wxMessageBox("Unable to load config style '"..fileDialog:GetPath().."'.",
"wxLua Error",
wx.wxOK + wx.wxCENTRE, ide.frame)
else
if (cfg.styles) then
ide.config.styles = StylesGetDefault()
-- copy
for i,s in pairs(cfg.styles) do
ide.config.styles[i] = s
end
end
if (cfg.stylesoutshell) then
ide.config.stylesoutshell = StylesGetDefault()
-- copy
for i,s in pairs(cfg.stylesoutshell) do
ide.config.stylesoutshell[i] = s
end
end
ReApplySpecAndStyles()
end
end
fileDialog:Destroy()
end
-- used lexers ?
--[=[
#define wxSTC_POV_DEFAULT 0
#define wxSTC_POV_COMMENT 1
#define wxSTC_POV_COMMENTLINE 2
#define wxSTC_POV_NUMBER 3
#define wxSTC_POV_OPERATOR 4
#define wxSTC_POV_IDENTIFIER 5
#define wxSTC_POV_STRING 6
#define wxSTC_POV_STRINGEOL 7
%define wxSTC_C_DEFAULT
%define wxSTC_C_COMMENT
%define wxSTC_C_COMMENTLINE
%define wxSTC_C_COMMENTDOC
%define wxSTC_C_NUMBER
%define wxSTC_C_WORD
%define wxSTC_C_STRING
%define wxSTC_C_CHARACTER
%define wxSTC_C_UUID
%define wxSTC_C_PREPROCESSOR
%define wxSTC_C_OPERATOR
%define wxSTC_C_IDENTIFIER
%define wxSTC_C_STRINGEOL
%define wxSTC_C_VERBATIM
%define wxSTC_C_REGEX
%define wxSTC_C_COMMENTLINEDOC
%define wxSTC_C_WORD2
%define wxSTC_C_COMMENTDOCKEYWORD
%define wxSTC_C_COMMENTDOCKEYWORDERROR
%define wxSTC_C_GLOBALCLASS
#define wxSTC_LUA_DEFAULT 0
#define wxSTC_LUA_COMMENT 1
#define wxSTC_LUA_COMMENTLINE 2
#define wxSTC_LUA_COMMENTDOC 3
#define wxSTC_LUA_NUMBER 4
#define wxSTC_LUA_WORD 5
#define wxSTC_LUA_STRING 6
#define wxSTC_LUA_CHARACTER 7
#define wxSTC_LUA_LITERALSTRING 8
#define wxSTC_LUA_PREPROCESSOR 9
#define wxSTC_LUA_OPERATOR 10
#define wxSTC_LUA_IDENTIFIER 11
#define wxSTC_LUA_STRINGEOL 12
]=]
-- authors: Luxinia Dev (Eike Decker & Christoph Kubisch)
---------------------------------------------------------
----------
-- Style
--
-- common style attributes
-- ---------------------------
-- fg foreground - {r,g,b} 0-255
-- bg background - {r,g,b} 0-255
-- u underline - boolean
-- b bold - boolean
-- i italic - boolean
-- fill fill to end - boolean
-- fn font Face Name - string ("Lucida Console")
-- fx font size - number (11)
-- hs turn hotspot on - true or {r,g,b} 0-255
-- v visibility for symbols of the current style - boolean
function StylesGetDefault()
return {
-- lexer specific (inherit fg/bg from text)
lexerdef = {fg = {128, 128, 128},},
comment = {fg = {0, 127, 0 },bg = {240, 240, 220}, fill= true,},
stringtxt = {fg = {127, 0, 127},},
stringeol = {fg = {0, 0, 0 },bg = {224, 192, 224}, fill = true, b = true},
preprocessor = {fg = {127, 127, 0 },},
operator = {fg = {0, 0, 0 },},
number = {fg = {90, 100, 0 },},
keywords0 = {fg = {0, 0, 127}, b = true,},
keywords1 = {fg = {127, 0, 0},},
keywords2 = {fg = {0, 127, 0},},
keywords3 = {fg = {0, 0, 127},},
keywords4 = {fg = {127, 0, 95},},
keywords5 = {fg = {35, 95, 175},},
keywords6 = {fg = {0, 127, 127},},
keywords7 = {fg = {240, 255, 255},},
-- common (inherit fg/bg from text)
text = nil, -- let os pick
linenumber = {fg = {192, 192, 192},},
bracematch = {fg = {0, 0, 255}, b = true},
bracemiss = {fg = {255, 0, 0 }, b = true},
escapechar = nil,
indent = {fg = {192, 192, 192},bg = {255, 255, 255},},
calltip = nil,
-- common special (need custom fg & bg )
calltipbg = nil,
sel = nil,
caret = nil,
caretlinebg = nil,
fold = nil,
whitespace = {fg = {180, 180, 180},},
-- indicators
fncall = {fg = {175,175,255}, st= wxstc.wxSTC_INDIC_BOX},
}
end
-- used to fill unset bg colors
local defaultfg = nil
local defaultbg = nil
local function applymarker(editor,marker,clrfg,clrbg)
if (clrfg) then
editor:MarkerSetForeground(marker,clrfg)
end
if (clrbg) then
editor:MarkerSetBackground(marker,clrbg)
end
end
local specialmapping = {
sel = function(editor,style)
if (style.fg) then
editor:SetSelForeground(1,wx.wxColour(unpack(style.fg)))
else
editor:SetSelForeground(0)
end
if (style.bg) then
editor:SetSelBackground(1,wx.wxColour(unpack(style.bg)))
else
editor:SetSelBackground(0)
end
end,
caret = function(editor,style)
if (style.fg) then
editor:SetCaretForeground(wx.wxColour(unpack(style.fg)))
end
--if (style.bg) then
-- editor:SetCaretBackground(wx.wxColour(unpack(style.bg)))
--end
end,
caretlinebg = function(editor,style)
if (style.bg) then
editor:SetCaretLineBackground(wx.wxColour(unpack(style.bg)))
end
end,
whitespace = function(editor,style)
if (style.fg) then
editor:SetWhitespaceForeground(1,wx.wxColour(unpack(style.fg)))
else
--editor:SetWhitespaceForeground(0)
end
if (style.bg) then
editor:SetWhitespaceBackground(1,wx.wxColour(unpack(style.bg)))
else
--editor:SetWhitespaceBackground(0)
end
end,
calltipbg = function(editor,style)
if (style.bg) then
editor:CallTipSetBackground(wx.wxColour(unpack(style.bg)))
end
end,
fold = function(editor,style)
local clrfg = style.fg and wx.wxColour(unpack(style.fg))
local clrbg = style.bg and wx.wxColour(unpack(style.bg))
if (clrfg or clrbg) then
applymarker(editor,wxstc.wxSTC_MARKNUM_FOLDEROPEN, clrfg,clrbg)
applymarker(editor,wxstc.wxSTC_MARKNUM_FOLDER, clrfg,clrbg)
applymarker(editor,wxstc.wxSTC_MARKNUM_FOLDERSUB, clrfg,clrbg)
applymarker(editor,wxstc.wxSTC_MARKNUM_FOLDERTAIL, clrfg,clrbg)
applymarker(editor,wxstc.wxSTC_MARKNUM_FOLDEREND, clrfg,clrbg)
applymarker(editor,wxstc.wxSTC_MARKNUM_FOLDEROPENMID, clrfg,clrbg)
applymarker(editor,wxstc.wxSTC_MARKNUM_FOLDERMIDTAIL, clrfg,clrbg)
end
end,
}
local defaultmapping = {
text = wxstc.wxSTC_STYLE_DEFAULT,
linenumber = wxstc.wxSTC_STYLE_LINENUMBER,
bracematch = wxstc.wxSTC_STYLE_BRACELIGHT,
bracemiss = wxstc.wxSTC_STYLE_BRACEBAD,
escapechar = wxstc.wxSTC_STYLE_CONTROLCHAR,
indent = wxstc.wxSTC_STYLE_INDENTGUIDE,
calltip = wxstc.wxSTC_STYLE_CALLTIP,
}
function StylesApplyToEditor(styles,editor,font,fontitalic,lexerconvert)
local function applystyle(style,id)
editor:StyleSetFont(id, style.i and fontitalic or font)
editor:StyleSetBold(id, style.b or false)
editor:StyleSetUnderline(id, style.u or false)
editor:StyleSetEOLFilled(id, style.fill or false)
if style.fn then editor:StyleSetFaceName(id, style.fn) end
if style.fs then editor:StyleSetSize(id, style.fs) end
if style.v ~= nil then editor:StyleSetVisible(id, style.v) end
if style.hs then
editor:StyleSetHotSpot(id, 1)
-- if passed a color (table) as value, set it as foreground
if type(style.hs) == 'table' then
local color = wx.wxColour(unpack(style.hs))
editor:SetHotspotActiveForeground(1, color)
end
editor:SetHotspotActiveUnderline(1)
editor:SetHotspotSingleLine(1)
end
if (style.fg or defaultfg) then
editor:StyleSetForeground(id, style.fg and wx.wxColour(unpack(style.fg)) or defaultfg)
end
if (style.bg or defaultbg) then
editor:StyleSetBackground(id, style.bg and wx.wxColour(unpack(style.bg)) or defaultbg)
end
end
editor:StyleResetDefault()
editor:SetFont(font)
if (styles.text) then
applystyle(styles.text,defaultmapping["text"])
else
applystyle({},defaultmapping["text"])
end
editor:StyleClearAll()
defaultfg = styles.text and styles.text.fg and wx.wxColour(unpack(styles.text.fg)) or nil
defaultbg = styles.text and styles.text.bg and wx.wxColour(unpack(styles.text.bg)) or nil
for name,style in pairs(styles) do
if (specialmapping[name]) then
specialmapping[name](editor,style)
elseif (defaultmapping[name]) then
applystyle(style,defaultmapping[name])
end
if (lexerconvert and lexerconvert[name]) then
local targets = lexerconvert[name]
for n,outid in pairs(targets) do
applystyle(style,outid)
end
-- allow to specify style numbers, but exclude those styles
-- that may conflict with indicator numbers
elseif (style.st and style.st > 8 and style.st < wxstc.wxSTC_STYLE_DEFAULT) then
applystyle(style,style.st)
end
end
do
editor:IndicatorSetStyle(0,styles.fncall and styles.fncall.st or wxstc.wxSTC_INDIC_BOX)
editor:IndicatorSetForeground(0,wx.wxColour(unpack(styles.fncall and styles.fncall.fg or {128,128,128})))
end
editor:Colourise(0, -1)
end
function ReApplySpecAndStyles()
local openDocuments = ide.openDocuments
for i,doc in pairs(openDocuments) do
if (doc.editor.spec) then
SetupKeywords(doc.editor,nil,doc.editor.spec)
end
end
local errorlog = ide.frame.bottomnotebook.errorlog
local shellbox = ide.frame.bottomnotebook.shellbox
SetupKeywords(shellbox,"lua",nil,ide.config.stylesoutshell,ide.ofont,ide.ofontItalic)
StylesApplyToEditor(ide.config.stylesoutshell,errorlog,ide.ofont,ide.ofontItalic)
end
function LoadConfigStyle()
local fileDialog = wx.wxFileDialog(ide.frame, "Open Config File",
"/cfg",
"",
"Lua file (*.lua)|*.lua|All files (*)|*",
wx.wxOPEN + wx.wxFILE_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())
if cfgfn then
setfenv(cfgfn,cfg)
cfgfn = xpcall(cfgfn,function(err)DisplayOutput("Error while executing configuration file: \n",debug.traceback(err))end)
end
if not (cfgfn and (cfg.styles or cfg.stylesoutshell)) then
wx.wxMessageBox("Unable to load config style '"..fileDialog:GetPath().."'.",
"Error",
wx.wxOK + wx.wxCENTRE, ide.frame)
else
if (cfg.styles) then
ide.config.styles = StylesGetDefault()
-- copy
for i,s in pairs(cfg.styles) do
ide.config.styles[i] = s
end
end
if (cfg.stylesoutshell) then
ide.config.stylesoutshell = StylesGetDefault()
-- copy
for i,s in pairs(cfg.stylesoutshell) do
ide.config.stylesoutshell[i] = s
end
end
ReApplySpecAndStyles()
end
end
fileDialog:Destroy()
end
-- used lexers ?
--[=[
#define wxSTC_POV_DEFAULT 0
#define wxSTC_POV_COMMENT 1
#define wxSTC_POV_COMMENTLINE 2
#define wxSTC_POV_NUMBER 3
#define wxSTC_POV_OPERATOR 4
#define wxSTC_POV_IDENTIFIER 5
#define wxSTC_POV_STRING 6
#define wxSTC_POV_STRINGEOL 7
%define wxSTC_C_DEFAULT
%define wxSTC_C_COMMENT
%define wxSTC_C_COMMENTLINE
%define wxSTC_C_COMMENTDOC
%define wxSTC_C_NUMBER
%define wxSTC_C_WORD
%define wxSTC_C_STRING
%define wxSTC_C_CHARACTER
%define wxSTC_C_UUID
%define wxSTC_C_PREPROCESSOR
%define wxSTC_C_OPERATOR
%define wxSTC_C_IDENTIFIER
%define wxSTC_C_STRINGEOL
%define wxSTC_C_VERBATIM
%define wxSTC_C_REGEX
%define wxSTC_C_COMMENTLINEDOC
%define wxSTC_C_WORD2
%define wxSTC_C_COMMENTDOCKEYWORD
%define wxSTC_C_COMMENTDOCKEYWORDERROR
%define wxSTC_C_GLOBALCLASS
#define wxSTC_LUA_DEFAULT 0
#define wxSTC_LUA_COMMENT 1
#define wxSTC_LUA_COMMENTLINE 2
#define wxSTC_LUA_COMMENTDOC 3
#define wxSTC_LUA_NUMBER 4
#define wxSTC_LUA_WORD 5
#define wxSTC_LUA_STRING 6
#define wxSTC_LUA_CHARACTER 7
#define wxSTC_LUA_LITERALSTRING 8
#define wxSTC_LUA_PREPROCESSOR 9
#define wxSTC_LUA_OPERATOR 10
#define wxSTC_LUA_IDENTIFIER 11
#define wxSTC_LUA_STRINGEOL 12
]=]

View File

@@ -1,311 +1,311 @@
-- authors: Luxinia Dev (Eike Decker & Christoph Kubisch)
---------------------------------------------------------
package.cpath = package.cpath..';bin/?.dll;bin/clibs/?.dll;bin/clibs/?/?.dll;bin/clibs/?/?/?.dll'
package.cpath = package.cpath..';bin/?.so;bin/clibs/?.so;bin/clibs/?/?.so;bin/clibs/?/?/?.so'
package.path = package.path..'lualibs/?.lua;lualibs/?/?.lua;lualibs/?/init.lua;lualibs/?/?/?.lua;lualibs/?/?/init.lua'
require("wx")
require("bit")
dofile "src/misc/util.lua"
-----------
-- IDE
--
-- Setup important defaults
dofile "src/editor/ids.lua"
dofile "src/editor/style.lua"
ide = {
config = {
path = {
projectdir = "",
app = nil,
},
editor = {
usetabs = true,
autotabs = true,
},
outputshell = {},
styles = StylesGetDefault(),
stylesoutshell = StylesGetDefault(),
interpreter = "EstrelaShell",
autocomplete = true,
acandtip = {
shorttip = false,
ignorecase = false,
strategy = 2,
},
filehistorylength = 20,
projecthistorylength = 15,
savebak = false,
singleinstance = true,
singleinstanceport = 0xe493,
view = {
vsplitterpos = 150,
splitterheight = 200,
},
setup = "",
},
specs = {
none = {
linecomment = ">",
sep = "\1",
}
},
tools = {
},
iofilters = {
},
interpreters = {
},
app = nil, -- application engine
interpreter = nil, -- current Lua interpreter
frame = nil, -- gui related
debugger = nil, -- debugger
filetree = nil, -- filetree
findReplace = nil, -- find & replace handling
settings = nil, -- user settings (window pos, last files..)
-- misc
exitingProgram = false, -- are we currently exiting, ID_EXIT
editorFilename = nil, -- the name of the wxLua program to be used when starting debugger
editorApp = wx.wxGetApp(),
openDocuments = {},-- open notebook editor documents[winId] = {
-- editor = wxStyledTextCtrl,
-- index = wxNotebook page index,
-- filePath = full filepath, nil if not saved,
-- fileName = just the filename,
-- modTime = wxDateTime of disk file or nil,
-- isModified = bool is the document modified? }
ignoredFilesList = {},
font = nil,
fontItalic = nil,
ofont = nil,
ofontItalic = nil,
}
-- load config
local function addConfig(filename,showerror,isstring)
local cfgfn,err = isstring and loadstring(filename) or loadfile(filename)
if not cfgfn then
if (showerror) then
print(("Error while loading configuration file: %s\n%s"):format(filename,err))
end
else
ide.config.os = os
ide.config.wxstc = wxstc
setfenv(cfgfn,ide.config)
xpcall(function()cfgfn(assert(_G))end,
function(err)
print("Error while executing configuration file: \n",
debug.traceback(err))end)
end
end
local function loadCFG()
addConfig("cfg/config.lua",true)
addConfig("cfg/user.lua",false)
end
loadCFG()
---------------
-- process args
local filenames = {}
do
local arg = {...}
ide.arg = arg
-- first argument must be the application name
assert(type(arg[1]) == "string","first argument must be application name")
ide.editorFilename = arg[1]
ide.config.path.app = arg[1]:match("([%w_-]+)%.?[^%.]*$")
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]
if #str < 4 then
print("Comandline: -cfg arg data not passed as string")
else
addConfig(str,true,true)
end
index = index+1
else
table.insert(filenames,arg[index])
end
end
end
----------------------
-- process application
ide.app = dofile(ide.config.path.app.."/app.lua")
local app = ide.app
assert(app)
do
local app = ide.app
function GetIDEString(keyword, default)
return app.stringtable[keyword] or default or keyword
end
end
----------------------
-- process plugins
local function addToTab(tab,file)
local cfgfn,err = loadfile(file)
if not cfgfn then
print(("Error while loading configuration file (%s): \n%s"):format(file,err))
else
local name = file:match("([a-zA-Z_0-9]+)%.lua$")
local success,result
success, result = xpcall(
function()return cfgfn(_G)end,
function(err)
print(("Error while executing configuration file (%s): \n%s"):
format(file,debug.traceback(err)))
end)
if (name and success) then
if (tab[name]) then
local out = tab[name]
for i,v in pairs(result) do
out[i] = v
end
else
tab[name] = result
end
end
end
end
-- load interpreters
local function loadInterpreters()
local files = FileSysGet(".\\interpreters\\*.*",wx.wxFILE)
for i,file in ipairs(files) do
if file:match "%.lua$" and app.loadfilters.interpreters(file) then
addToTab(ide.interpreters,file)
end
end
end
loadInterpreters()
-- load specs
local function loadSpecs()
local files = FileSysGet(".\\spec\\*.*",wx.wxFILE)
for i,file in ipairs(files) do
if file:match "%.lua$" and app.loadfilters.specs(file) then
addToTab(ide.specs,file)
end
end
for n,spec in pairs(ide.specs) do
spec.sep = spec.sep or ""
spec.iscomment = {}
spec.iskeyword0 = {}
if (spec.lexerstyleconvert) then
if (spec.lexerstyleconvert.comment) then
for i,s in pairs(spec.lexerstyleconvert.comment) do
spec.iscomment[s] = true
end
end
if (spec.lexerstyleconvert.keywords0) then
for i,s in pairs(spec.lexerstyleconvert.keywords0) do
spec.iskeyword0[s] = true
end
end
end
end
end
loadSpecs()
-- load tools
local function loadTools()
local files = FileSysGet(".\\tools\\*.*",wx.wxFILE)
for i,file in ipairs(files) do
if file:match "%.lua$" and app.loadfilters.tools(file) then
addToTab(ide.tools,file)
end
end
end
loadTools()
---------------
-- Load App
dofile "src/editor/settings.lua"
dofile "src/editor/singleinstance.lua"
dofile "src/editor/iofilters.lua"
dofile "src/editor/gui.lua"
dofile "src/editor/output.lua"
dofile "src/editor/debugger.lua"
dofile "src/editor/filetree.lua"
dofile "src/editor/preferences.lua"
dofile "src/editor/editor.lua"
dofile "src/editor/autocomplete.lua"
dofile "src/editor/findreplace.lua"
dofile "src/editor/commands.lua"
dofile "src/editor/shellbox.lua"
dofile "src/editor/menu.lua"
dofile "src/preferences/editor.lua"
dofile "src/preferences/project.lua"
-- load rest of settings
SettingsRestoreEditorSettings()
SettingsRestoreFramePosition(ide.frame, "MainFrame")
SettingsRestoreView()
SettingsRestoreFileSession(SetOpenFiles)
SettingsRestoreFileHistory(UpdateFileHistoryUI)
SettingsRestoreProjectSession(SetProjects)
-- ---------------------------------------------------------------------------
-- Load the filenames
do
local notebook = ide.frame.vsplitter.splitter.notebook
local loaded
for i,fileName in ipairs(filenames) do
if fileName ~= "--" then
LoadFile(fileName, nil, true)
loaded = true
end
end
if notebook:GetPageCount() > 0 then
else
local editor = CreateEditor("untitled.lua")
SetupKeywords(editor, "lua")
end
end
ide.frame:Show(true)
app.postinit()
-- 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.
wx.wxGetApp():MainLoop()
-- authors: Luxinia Dev (Eike Decker & Christoph Kubisch)
---------------------------------------------------------
package.cpath = package.cpath..';bin/?.dll;bin/clibs/?.dll;bin/clibs/?/?.dll;bin/clibs/?/?/?.dll'
package.cpath = package.cpath..';bin/?.so;bin/clibs/?.so;bin/clibs/?/?.so;bin/clibs/?/?/?.so'
package.path = package.path..';lualibs/?.lua;lualibs/?/?.lua;lualibs/?/init.lua;lualibs/?/?/?.lua;lualibs/?/?/init.lua'
require("wx")
require("bit")
dofile "src/misc/util.lua"
-----------
-- IDE
--
-- Setup important defaults
dofile "src/editor/ids.lua"
dofile "src/editor/style.lua"
ide = {
config = {
path = {
projectdir = "",
app = nil,
},
editor = {
usetabs = true,
autotabs = true,
},
debugger = {
verbose = false,
},
outputshell = {},
styles = StylesGetDefault(),
stylesoutshell = StylesGetDefault(),
interpreter = "_undefined_",
autocomplete = true,
acandtip = {
shorttip = false,
ignorecase = false,
strategy = 2,
},
activateoutput = false, -- activate output/console on Run/Debug/Compile
filehistorylength = 20,
projecthistorylength = 15,
savebak = false,
singleinstance = false,
singleinstanceport = 0xe493,
},
specs = {
none = {
linecomment = ">",
sep = "\1",
}
},
tools = {
},
iofilters = {
},
interpreters = {
},
app = nil, -- application engine
interpreter = nil, -- current Lua interpreter
frame = nil, -- gui related
debugger = {}, -- debugger related info
filetree = nil, -- filetree
findReplace = nil, -- find & replace handling
settings = nil, -- user settings (window pos, last files..)
-- misc
exitingProgram = false, -- are we currently exiting, ID_EXIT
editorApp = wx.wxGetApp(),
editorFilename = nil,
openDocuments = {},-- open notebook editor documents[winId] = {
-- editor = wxStyledTextCtrl,
-- index = wxNotebook page index,
-- filePath = full filepath, nil if not saved,
-- fileName = just the filename,
-- modTime = wxDateTime of disk file or nil,
-- isModified = bool is the document modified? }
ignoredFilesList = {},
font = nil,
fontItalic = nil,
ofont = nil,
ofontItalic = nil,
}
---------------
-- process args
local filenames = {}
local configs = {}
do
local arg = {...}
ide.arg = arg
-- first argument must be the application name
assert(type(arg[1]) == "string","first argument must be application name")
ide.editorFilename = arg[1]
ide.config.path.app = arg[1]:match("([%w_-]+)%.?[^%.]*$")
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]
if #str < 4 then
print("Comandline: -cfg arg data not passed as string")
else
table.insert(configs,str)
end
index = index+1
else
table.insert(filenames,arg[index])
end
end
end
-----------------------
-- load config
local function addConfig(filename,showerror,isstring)
local cfgfn,err = isstring and loadstring(filename) or loadfile(filename)
if not cfgfn then
if (showerror) then
print(("Error while loading configuration file: %s\n%s"):format(filename,err))
end
else
ide.config.os = os
ide.config.wxstc = wxstc
setfenv(cfgfn,ide.config)
xpcall(function()cfgfn(assert(_G))end,
function(err)
print("Error while executing configuration file: \n",
debug.traceback(err))
end)
end
end
do
addConfig(ide.config.path.app.."/config.lua",true)
addConfig("cfg/user.lua",false)
for i,v in ipairs(configs) do
addConfig(v,true,true)
end
configs = nil
end
----------------------
-- process application
ide.app = dofile(ide.config.path.app.."/app.lua")
local app = ide.app
assert(app)
do
local app = ide.app
function GetIDEString(keyword, default)
return app.stringtable[keyword] or default or keyword
end
end
----------------------
-- process plugins
local function addToTab(tab,file)
local cfgfn,err = loadfile(file)
if not cfgfn then
print(("Error while loading configuration file (%s): \n%s"):format(file,err))
else
local name = file:match("([a-zA-Z_0-9]+)%.lua$")
local success,result
success, result = xpcall(
function()return cfgfn(_G)end,
function(err)
print(("Error while executing configuration file (%s): \n%s"):
format(file,debug.traceback(err)))
end)
if (name and success) then
if (tab[name]) then
local out = tab[name]
for i,v in pairs(result) do
out[i] = v
end
else
tab[name] = result
end
end
end
end
-- load interpreters
local function loadInterpreters()
local files = FileSysGet(".\\interpreters\\*.*",wx.wxFILE)
for i,file in ipairs(files) do
if file:match "%.lua$" and app.loadfilters.interpreters(file) then
addToTab(ide.interpreters,file)
end
end
end
loadInterpreters()
-- load specs
local function loadSpecs()
local files = FileSysGet(".\\spec\\*.*",wx.wxFILE)
for i,file in ipairs(files) do
if file:match "%.lua$" and app.loadfilters.specs(file) then
addToTab(ide.specs,file)
end
end
for n,spec in pairs(ide.specs) do
spec.sep = spec.sep or ""
spec.iscomment = {}
spec.iskeyword0 = {}
if (spec.lexerstyleconvert) then
if (spec.lexerstyleconvert.comment) then
for i,s in pairs(spec.lexerstyleconvert.comment) do
spec.iscomment[s] = true
end
end
if (spec.lexerstyleconvert.keywords0) then
for i,s in pairs(spec.lexerstyleconvert.keywords0) do
spec.iskeyword0[s] = true
end
end
end
end
end
loadSpecs()
-- load tools
local function loadTools()
local files = FileSysGet(".\\tools\\*.*",wx.wxFILE)
for i,file in ipairs(files) do
if file:match "%.lua$" and app.loadfilters.tools(file) then
addToTab(ide.tools,file)
end
end
end
loadTools()
if app.preinit then app.preinit() end
---------------
-- Load App
dofile "src/editor/settings.lua"
dofile "src/editor/singleinstance.lua"
dofile "src/editor/iofilters.lua"
dofile "src/editor/gui.lua"
dofile "src/editor/filetree.lua"
dofile "src/editor/output.lua"
dofile "src/editor/debugger.lua"
dofile "src/editor/preferences.lua"
dofile "src/editor/editor.lua"
dofile "src/editor/autocomplete.lua"
dofile "src/editor/findreplace.lua"
dofile "src/editor/commands.lua"
dofile "src/editor/shellbox.lua"
dofile "src/editor/menu.lua"
dofile "src/preferences/editor.lua"
dofile "src/preferences/project.lua"
dofile "src/version.lua"
-- load rest of settings
SettingsRestoreEditorSettings()
SettingsRestoreFramePosition(ide.frame, "MainFrame")
SettingsRestoreFileSession(SetOpenFiles)
SettingsRestoreFileHistory(UpdateFileHistoryUI)
SettingsRestoreProjectSession(FileTreeSetProjects)
SettingsRestoreView()
-- ---------------------------------------------------------------------------
-- Load the filenames
do
local notebook = ide.frame.notebook
local loaded
for i,fileName in ipairs(filenames) do
if fileName ~= "--" then
LoadFile(fileName, nil, true)
loaded = true
end
end
if notebook:GetPageCount() == 0 then
local editor = CreateEditor("untitled.lua")
SetupKeywords(editor, "lua")
end
end
if app.postinit then app.postinit() 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.
wx.wxGetApp():MainLoop()

View File

@@ -1,175 +1,189 @@
-- authors: Lomtik Software (J. Winwood & John Labenski)
-- Luxinia Dev (Eike Decker & Christoph Kubisch)
-- David Manura
---------------------------------------------------------
-- Equivalent to C's "cond ? a : b", all terms will be evaluated
function iff(cond, a, b) if cond then return a else return b end end
-- Does the num have all the bits in value
function HasBit(value, num)
for n = 32, 0, -1 do
local b = 2^n
local num_b = num - b
local value_b = value - b
if num_b >= 0 then
num = num_b
else
return true -- already tested bits in num
end
if value_b >= 0 then
value = value_b
end
if (num_b >= 0) and (value_b < 0) then
return false
end
end
return true
end
-- ASCII values for common chars
char_CR = string.byte("\r")
char_LF = string.byte("\n")
char_Tab = string.byte("\t")
char_Sp = string.byte(" ")
string_Pathsep = string.char(wx.wxFileName.GetPathSeparator())
stringset_File = '[^"%?%*:\\/<>|]'
function StripCommentsC(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
-- http://lua-users.org/wiki/EnhancedFileLines
function FileLines(f)
local CHUNK_SIZE = 1024
local buffer = ""
local pos_beg = 1
return function()
local pos, chars
while 1 do
pos, chars = buffer:match('()([\r\n].)', pos_beg)
if pos or not f then
break
elseif f then
local chunk = f:read(CHUNK_SIZE)
if chunk then
buffer = buffer:sub(pos_beg) .. chunk
pos_beg = 1
else
f = nil
end
end
end
if not pos then
pos = #buffer
elseif chars == '\r\n' then
pos = pos + 1
end
local line = buffer:sub(pos_beg, pos)
pos_beg = pos + 1
if #line > 0 then
return line
end
end
end
function PrependStringToArray(t, s, maxstrings)
if string.len(s) == 0 then return end
for i, v in ipairs(t) do
if v == s then
table.remove(t, i) -- remove old copy
break
end
end
table.insert(t, 1, s)
if #t > (maxstrings or 15) then table.remove(t, #t) end -- keep reasonable length
end
-- ----------------------------------------------------------------------------
-- Get file modification time, returns a wxDateTime (check IsValid) or nil if
-- the file doesn't exist
function GetFileModTime(filePath)
if filePath and (string.len(filePath) > 0) then
local fn = wx.wxFileName(filePath)
if fn:FileExists() then
return fn:GetModificationTime()
end
end
return nil
end
function GetFileExt(filePath)
local match = filePath and filePath:match("%.([a-zA-Z_0-9]+)$")
return match and (string.lower(match))
end
function IsLuaFile(filePath)
return filePath and (string.len(filePath) > 4) and
(string.lower(string.sub(filePath, -4)) == ".lua")
end
function GetFileNameExt(filePath)
if (not filePath) then return end
local wxn = wx.wxFileName(filePath)
return (wxn:GetName()..(wxn:HasExt() and ("."..wxn:GetExt()) or ""))
end
function GetPathWithSep(wxfn)
return wxfn:GetPath(bit.bor(wx.wxPATH_GET_VOLUME, wx.wxPATH_GET_SEPARATOR))
end
function FileSysHasContent(dir)
local f = wx.wxFindFirstFile(dir,wx.wxFILE + wx.wxDIR)
return #f>0
end
function FileSysGet(dir,spec)
local content = {}
local browse = wx.wxFileSystem()
local f = browse:FindFirst(dir,spec)
while #f>0 do
table.insert(content,f)
f = browse:FindNext()
end
return content
end
-- authors: Lomtik Software (J. Winwood & John Labenski)
-- Luxinia Dev (Eike Decker & Christoph Kubisch)
-- David Manura
---------------------------------------------------------
-- Equivalent to C's "cond ? a : b", all terms will be evaluated
function iff(cond, a, b) if cond then return a else return b end end
-- Does the num have all the bits in value
function HasBit(value, num)
for n = 32, 0, -1 do
local b = 2^n
local num_b = num - b
local value_b = value - b
if num_b >= 0 then
num = num_b
else
return true -- already tested bits in num
end
if value_b >= 0 then
value = value_b
end
if (num_b >= 0) and (value_b < 0) then
return false
end
end
return true
end
-- ASCII values for common chars
char_CR = string.byte("\r")
char_LF = string.byte("\n")
char_Tab = string.byte("\t")
char_Sp = string.byte(" ")
string_Pathsep = string.char(wx.wxFileName.GetPathSeparator())
stringset_File = '[^"%?%*:\\/<>|]'
function StripCommentsC(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
-- http://lua-users.org/wiki/EnhancedFileLines
function FileLines(f)
local CHUNK_SIZE = 1024
local buffer = ""
local pos_beg = 1
return function()
local pos, chars
while 1 do
pos, chars = buffer:match('()([\r\n].)', pos_beg)
if pos or not f then
break
elseif f then
local chunk = f:read(CHUNK_SIZE)
if chunk then
buffer = buffer:sub(pos_beg) .. chunk
pos_beg = 1
else
f = nil
end
end
end
if not pos then
pos = #buffer
elseif chars == '\r\n' then
pos = pos + 1
end
local line = buffer:sub(pos_beg, pos)
pos_beg = pos + 1
if #line > 0 then
return line
end
end
end
function PrependStringToArray(t, s, maxstrings)
if string.len(s) == 0 then return end
for i, v in ipairs(t) do
if v == s then
table.remove(t, i) -- remove old copy
break
end
end
table.insert(t, 1, s)
if #t > (maxstrings or 15) then table.remove(t, #t) end -- keep reasonable length
end
-- ----------------------------------------------------------------------------
-- Get file modification time, returns a wxDateTime (check IsValid) or nil if
-- the file doesn't exist
function GetFileModTime(filePath)
if filePath and (string.len(filePath) > 0) then
local fn = wx.wxFileName(filePath)
if fn:FileExists() then
return fn:GetModificationTime()
end
end
return nil
end
function GetFileExt(filePath)
local match = filePath and filePath:match("%.([a-zA-Z_0-9]+)$")
return match and (string.lower(match))
end
function IsLuaFile(filePath)
return filePath and (string.len(filePath) > 4) and
(string.lower(string.sub(filePath, -4)) == ".lua")
end
function GetFileNameExt(filePath)
if (not filePath) then return end
local wxn = wx.wxFileName(filePath)
return (wxn:GetName()..(wxn:HasExt() and ("."..wxn:GetExt()) or ""))
end
function GetPathWithSep(wxfn)
return wxfn:GetPath(bit.bor(wx.wxPATH_GET_VOLUME, wx.wxPATH_GET_SEPARATOR))
end
function FileSysHasContent(dir)
local f = wx.wxFindFirstFile(dir,wx.wxFILE + wx.wxDIR)
return #f>0
end
function FileSysGet(dir,spec)
local content = {}
local browse = wx.wxFileSystem()
if not wx.wxFileName(dir):DirExists() then
return content
end
local f = browse:FindFirst(dir,spec)
while #f>0 do
table.insert(content,f)
f = browse:FindNext()
end
return content
end
function pairsSorted(t, f)
local a = {}
for n in pairs(t) do table.insert(a, n) end
table.sort(a, f)
local i = 0 -- iterator variable
local iter = function () -- iterator function
i = i + 1
if a[i] == nil then return nil
else return a[i], t[a[i]]
end
end
return iter
end

View File

@@ -2,25 +2,22 @@
---------------------------------------------------------
preferencesDialog.addCategory {
category = "editor";
title = "Editor";
category = "editor";
title = "Editor";
}
preferencesDialog.addPage {
title = "Basic preferences";
category = "editor";
layout = {
{type = 'group',title="Sessions"; minheight = 100; minwidth = 100};
{type = "checkbox"; title = "Reopen files";name = 'session_restore'};
{type = 'finishgroup'};
{type = 'space'; space = 4};
};
onload = function ()
return {testbox = true}
end;
onsave = function (values)
end
title = "Basic preferences";
category = "editor";
layout = {
{type = 'group',title="Sessions"; minheight = 100; minwidth = 100};
{type = "checkbox"; title = "Reopen files";name = 'session_restore'};
{type = 'finishgroup'};
{type = 'space'; space = 4};
};
onload = function ()
return {testbox = true}
end;
onsave = function (values)
end
}

View File

@@ -2,36 +2,36 @@
---------------------------------------------------------
preferencesDialog.addCategory {
category = "project";
title = "Project";
category = "project";
title = "Project";
}
preferencesDialog.addPage {
title = "Project settings";
category = "project";
layout = {
{type = 'group',title="Visible menus"; minheight = 100; minwidth = 100};
{type = "checkbox"; title = "Tools";name = 'tools'};
{type = 'linebreak'; space = 4};
{type = "checkbox"; title = "Help";name = 'help'};
{type = 'linebreak'; space = 4};
--{type='static'; title = "foo"};
{type = 'finishgroup'};
{type = "space"; space = 4};
{type = 'group',title="Interpreter"; minheight = 100; minwidth = 100};
{type = "static"; title = "Interpreter"};
{type = "space"; space = 4};
{type = "combobox"; name = "interpreterlist"};
{type = 'linebreak'; space = 4};
{type = "static";title = "Working directory"};
{type = "dirpicker"; name = "workingdir", title='Working directory'};
{type = 'linebreak'; space = 4};
{type = "static"; title = "Argument"};
{type = "edit"; name = "argument"};
{type = 'finishgroup'};
};
onload = function () return {
interpreterlist = {"1","2"}
} end;
onsave = function (values) end;
title = "Project settings";
category = "project";
layout = {
{type = 'group',title="Visible menus"; minheight = 100; minwidth = 100};
{type = "checkbox"; title = "Tools";name = 'tools'};
{type = 'linebreak'; space = 4};
{type = "checkbox"; title = "Help";name = 'help'};
{type = 'linebreak'; space = 4};
--{type='static'; title = "foo"};
{type = 'finishgroup'};
{type = "space"; space = 4};
{type = 'group',title="Interpreter"; minheight = 100; minwidth = 100};
{type = "static"; title = "Interpreter"};
{type = "space"; space = 4};
{type = "combobox"; name = "interpreterlist"};
{type = 'linebreak'; space = 4};
{type = "static";title = "Working directory"};
{type = "dirpicker"; name = "workingdir", title='Working directory'};
{type = 'linebreak'; space = 4};
{type = "static"; title = "Argument"};
{type = "edit"; name = "argument"};
{type = 'finishgroup'};
};
onload = function () return {
interpreterlist = {"1","2"}
} end;
onsave = function (values) end;
}

1
src/version.lua Normal file
View File

@@ -0,0 +1 @@
ide.VERSION = [[devel]]

Some files were not shown because too many files have changed in this diff Show More