Compare commits
102 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8419287316 | ||
|
|
27d1d159f6 | ||
|
|
491d37038a | ||
|
|
67eee4f9ef | ||
|
|
552a7373ca | ||
|
|
376a25dfdd | ||
|
|
7945a09811 | ||
|
|
327f650121 | ||
|
|
9bceb449e8 | ||
|
|
4278c25c60 | ||
|
|
7f47506eae | ||
|
|
b0b137eaf1 | ||
|
|
d1d29ced43 | ||
|
|
2795d4d9ce | ||
|
|
02845f2e87 | ||
|
|
ec46531c55 | ||
|
|
9895f06f97 | ||
|
|
a67feb86aa | ||
|
|
6b990b652c | ||
|
|
7a2326cc9e | ||
|
|
e129f486d9 | ||
|
|
c09d9fc143 | ||
|
|
52ef014941 | ||
|
|
e79fedf764 | ||
|
|
b7544577df | ||
|
|
53110b3b2f | ||
|
|
d6ee3d1278 | ||
|
|
c0109a26d1 | ||
|
|
2a706f5bf3 | ||
|
|
1f266e04ab | ||
|
|
f45d6f84a3 | ||
|
|
76b8b7b07b | ||
|
|
d45f893943 | ||
|
|
53e725cf03 | ||
|
|
8a66df19fa | ||
|
|
13be57ae39 | ||
|
|
684150714f | ||
|
|
01e23f448e | ||
|
|
036ec3534a | ||
|
|
af57806c69 | ||
|
|
a4773563e9 | ||
|
|
195c463a60 | ||
|
|
8cbf20ae42 | ||
|
|
a11bd6f0d3 | ||
|
|
1fc12a8a76 | ||
|
|
9a1e681569 | ||
|
|
43083742e6 | ||
|
|
9a5b481189 | ||
|
|
565f8e74fb | ||
|
|
b1b87e9013 | ||
|
|
539eddbf9d | ||
|
|
0abcff015e | ||
|
|
7bb74b5fb4 | ||
|
|
b9bc6454b4 | ||
|
|
5734455818 | ||
|
|
e6e0870a11 | ||
|
|
2c45207436 | ||
|
|
bf09d3748c | ||
|
|
452f99826e | ||
|
|
bbfc1c3624 | ||
|
|
429bb24cb4 | ||
|
|
2a8e7fe423 | ||
|
|
cf1a657b80 | ||
|
|
cf6b328a52 | ||
|
|
b0f98f30dc | ||
|
|
5c0bf93d9c | ||
|
|
7b2241085d | ||
|
|
c9cfd42d34 | ||
|
|
c25c56069d | ||
|
|
a68e8f7bd3 | ||
|
|
fc6de036e0 | ||
|
|
08d42a2501 | ||
|
|
da32878984 | ||
|
|
3fd5d88656 | ||
|
|
7d9ad5100c | ||
|
|
6bff634446 | ||
|
|
b0de487bf0 | ||
|
|
560d56835a | ||
|
|
3c6a06f537 | ||
|
|
b1f3bf0bd9 | ||
|
|
6ea3a4708d | ||
|
|
4de0eb1dc0 | ||
|
|
c2f6ed6338 | ||
|
|
fad7ff0cc3 | ||
|
|
9afa35f9b2 | ||
|
|
3a5b46f65e | ||
|
|
26d0908c89 | ||
|
|
770db579d9 | ||
|
|
8e09ed1658 | ||
|
|
25ac96d39a | ||
|
|
22fda661ec | ||
|
|
529a0e8c9e | ||
|
|
7cc061e18d | ||
|
|
5f2226bac2 | ||
|
|
37795c2480 | ||
|
|
5e934dfd69 | ||
|
|
f970ba38a0 | ||
|
|
8af6c1b5b6 | ||
|
|
0777a5fbd8 | ||
|
|
942681e246 | ||
|
|
46da5b6697 | ||
|
|
80f83d781e |
235
CHANGELOG.md
Normal file
235
CHANGELOG.md
Normal file
@@ -0,0 +1,235 @@
|
||||
# ZeroBrane Studio Changelog
|
||||
|
||||
## v0.32 (Sep 03 2012)
|
||||
|
||||
### Highlights
|
||||
- Added **Unicode support** for file encoding and file paths on Windows (fixes #30).
|
||||
- Added **Moai integration and debugging** (including debugging of Moai threads and callbacks).
|
||||
- Added refresh of Stack and Watch windows after executing a statement in remote shell.
|
||||
- Added **display of complex values** on multiple lines in shell with '='.
|
||||
- Added calltip on mouseover for functions during editing and for variables/expressions during debugging.
|
||||
- Added configuration options to set paths to lua and love2d executables.
|
||||
- Added support for **coroutine debugging** with stepping through coroutine.resume/.yield calls.
|
||||
- Updated wx.dll to wxlua 2.8.12.2 and wxwidgets 2.8.12.
|
||||
- Signed zbstudio app and executable to avoid issues with files not being saved without admin privileges and to remove warning about 'unknown publisher' on windows (fixes #25).
|
||||
|
||||
### Improvements
|
||||
- Added calltip on mouseover for functions during editing and for variables/expressions during debugging.
|
||||
- Added an IO filter to fix an issue with 0d0d0a line endings on Windows.
|
||||
- Added support for debugging moai callbacks (upgraded to mobdebug v0.489).
|
||||
- Added refresh of Stack and Watch windows to show updated values after executing a statement in remote shell.
|
||||
- Added display of complex values on multiple lines in shell with '='.
|
||||
- Added rockspec to the list of extensions for lua (fixes #37).
|
||||
- Added a check to avoid evaluating keywords in tooltip.
|
||||
- Added current interpreter to the status bar; adding closing debugger when the interpreter is changed.
|
||||
- Added aborting scratchpad processing when an interpreter can't start or report a fatal error.
|
||||
- Added support for unicode path files on Windows (fixes #30).
|
||||
- Added an option to set path to lua executable.
|
||||
- Added error handler to trap and display debugger errors.
|
||||
- Added search in PATH for love2d executable.
|
||||
- Added a workaround for GetExecutablePath() reporting 'wx.dll' instead of a proper exe name with wxlua 2.8.12.2 on Windows.
|
||||
- Added reporting of function name of the form a.b and a:b in static analysis (fixes #27).
|
||||
- Added ability for user to keep their settings file in their home directory.
|
||||
- Added per user settings file. Users can now move their settings file to ~/.zbs/user.lua.
|
||||
- Added ignoring Cmd-key combinations on Mac as this should be handled by wxwidgets, but is not (fixes #19).
|
||||
- Added support for coroutine debugging with stepping through coroutine.resume/.yield calls.
|
||||
- Changed reporting of program execution time from CPU time to user time.
|
||||
- Changed the call to unhide windows to the async version (ShowWindowAsync) to avoid blocking the IDE when the application doesn't respond.
|
||||
- Upgraded to wxlua 2.8.12.2 (wxwidgets 2.8.12; unicode version); added lua51.dll proxy (fixes #10 and #7).
|
||||
- Updated love2d interpreter to use the project folder to check for main.lua.
|
||||
- Updated test module to use stringified values for comparison.
|
||||
- Updated status bar style to make it consistent across platforms.
|
||||
- Removed .bak files from being replaced in when backup copies are saved.
|
||||
- Removed explicit path conversions and comparisons.
|
||||
- Refactored LUA_PATH/CPATH processing to set it for all interpreters.
|
||||
- Signed zbstudio app and executable to avoid issues with files not being saved without admin privileges and to remove warning about 'unknown publisher' on windows (fixes #25).
|
||||
|
||||
### Incompatibilities
|
||||
- Reassigned hotkeys in the Project menu to minimize conflicts on Mac (reassigned Shift-F12 and F11).
|
||||
|
||||
### Fixes
|
||||
- Fixed an issue with double click on analylsis results being out-of-sync when the editor switched to another file (fixes #38)
|
||||
- Fixed an issue with debugger not activating files with relative path information.
|
||||
- Fixed 'break' command to work after coming from debugger calls (like on()).
|
||||
- Fixed an issue with highlighting selected item in the project tree.
|
||||
- Fixed evaluation of foo:bar in tooltip (now evaluates as foo.bar).
|
||||
- Fixed debugger termination after internal errors.
|
||||
- Fixed activating current file in the project tree on Mac (closes #29).
|
||||
- Fixed running scripts with single quotes in path names.
|
||||
- Fixed an issue with Run/Debug commands when IDE path includes exclamation mark ('!').
|
||||
- Fixed an issue with the app not starting on those systems that don't have HOME environment variable; fixes #28.
|
||||
- Fixed an issue with showing/hiding GUI windows that was occasionally causing a runtime error when the window disappears before it is manipulated.
|
||||
- Fixed returning proper name for unsaved files in reporting compilation and static analysis results; moved default names to ide.config (fixes #26).
|
||||
- Fixed pasting text into the Find dialog and project path box on Mac (fixes #22).
|
||||
- Fixed handling of dashes in paths (upgraded to mobdebug 0.479).
|
||||
- Reorganized handling of automcomplete event (to use AddPendingEvent instead of PostEvent) to avoid runtime application error.
|
||||
|
||||
## v0.31 (Jul 14 2012)
|
||||
|
||||
### Highlights
|
||||
- Added **scratchpad support for love2d**.
|
||||
- Added tooltip to display variable/expression values during debugging.
|
||||
- Added **MacOS support**.
|
||||
|
||||
### Improvements
|
||||
- Added handling of balanced brackets in markup links.
|
||||
- Added unit test module.
|
||||
- Added reporting the number of traced lines during debugging.
|
||||
- Added setting of PATH and CPATH to find proper libs on windows and mac os platforms.
|
||||
- Added scratchpad support for love2d.
|
||||
- Added reset of 'modified' status to keep tab names and their config settings correct upon exit.
|
||||
- Added window title update and filetree refresh after SaveAs command.
|
||||
- Added tooltip to display variable/expression values during debugging.
|
||||
- Made 'View Stack Window' and 'View Watch Window' refresh window content if it's already shown.
|
||||
- Removed setting the editor font in the config as the default font is different on different platforms.
|
||||
- Removed extension from the template to match folders to make it more portable.
|
||||
- Reorganized handling of font configuration and added font config for filetree (with a different size default on MacOS).
|
||||
- Updated matching logic for function definitions to allow for a.b.c() definitions (fixes #17).
|
||||
|
||||
### Fixes
|
||||
- Fixed markup styling and file tree drawing on MacOS.
|
||||
- Fixed detecting executable name in commands with spaces.
|
||||
- Fixed incorrect folders reported in the file tree when no project directory is set and a file is open.
|
||||
- Fixed incorrect filename reported in compile errors when the file is not saved.
|
||||
- Fixed refresh of filetree on MacOS to get it displayed correctly when the app is started.
|
||||
- Fixed an error thrown when a window with debugging is closed before the application being debugged is terminated.
|
||||
- Fixed incorrect storing of settings for editor tabs with the same text (filename). This was causing only one tab displayed for multiple StyledText controls with interesting effects.
|
||||
- Fixed an issue with launching a process when its output is not redirected to the IDE (fixes #16).
|
||||
- Fixed console to evaluate 'function a() ... end' without errors.
|
||||
- Fixed a compilation error caused by shebang in scripts.
|
||||
- Fixed an issue with love2d path with spaces.
|
||||
- Corrected resetting of project directory when it's already set and doesn't need to be changed.
|
||||
- Added checks around ShowFullScreen() calls to avoid failures on those systems that don't provide it (linux/GTK).
|
||||
- Added check for debugger calls to avoid errors when debugger is not loaded.
|
||||
- Updated matching of links to make them less greedy (to avoid capturing link terminators).
|
||||
- Upgraded deprecated constants and logic for compatibility with wxwidgets 2.9.x.
|
||||
- Reset project directory if the current one doesn't exist.
|
||||
- Removed styling of function calls and capturing definitions in strings and comments (fixed #18).
|
||||
- Removed setting focus to the Output window when output is processed as it interfered with Run as Scratchpad.
|
||||
|
||||
## v0.30 (Jun 27 2012)
|
||||
|
||||
### Highlights
|
||||
- Added **love2d support**.
|
||||
- Added auto complete for love2d API.
|
||||
- Added support for debugging processes running under LuaJIT.
|
||||
- Added display of **hierarchical data in Stack window**.
|
||||
- Added **pretty printing in Watch and Console** (local and remote) windows and handling of multiple results in Console.
|
||||
- Added **Stack window to display stack information** and local/upvalue values for each stack frame.
|
||||
- Added ability to **interact with scripts** by allowing text to be entered in the 'Output' window.
|
||||
|
||||
### Improvements
|
||||
- Added love2d support.
|
||||
- Added auto complete for love2d API.
|
||||
- Added support for debugging processes running under LuaJIT.
|
||||
- Added display of hierarchical data in Stack window.
|
||||
- Added execution time and updated messages in the Output window to be more consistent.
|
||||
- Added displaying 'nil' values in local console when no result is returned by an expression.
|
||||
- Added a check to refuse starting a new debugging session if there is one in progress already.
|
||||
- Added handling of tail calls in the Stack window.
|
||||
- Added pretty printing in Watch and Console (local and remote) windows and handling of multiple results in Console.
|
||||
- Added Stack window to display stack information and local/upvalue values for each stack frame.
|
||||
- Added ability to set font encoding in the config.
|
||||
- Added restoring cursor position when a modified file is reloaded in the editor.
|
||||
- Added ability to interact with scripts by allowing text to be entered in the 'Output' window.
|
||||
- Improved logic in love2d integration to distinguish Debug and Run commands (closes #13).
|
||||
- Improved reporting in static analysis for functions and global variables.
|
||||
- Updated menus to avoid conflicts with MacOS shortcuts.
|
||||
- Updated logic creating menubar to make it work correctly on MacOS with special Help/About items.
|
||||
- Updated path handling to better detect how the app is started and to avoid loading dlls on non-windows platforms.
|
||||
- Updated logic for detecting hostname (used in the debugger) to make sure it is resolvable.
|
||||
- Changed order of lualibs/ and bin/ directories in package.path and package.cpath to load included modules first.
|
||||
- Removed extensions from launch commands and updated display logic in the Output window.
|
||||
|
||||
### Fixes
|
||||
- Fixed aborting running/debugged programs on MacOS by adding MAKE_GROUP_LEADER option to wxExecute.
|
||||
- Fixed an issue in the logic for setting breakpoints, which ignored breakpoints in luxinia2 debug sessions.
|
||||
- Fixed logic in the local/remote console that returned incorrect error message on executing code like '%s':format(1).
|
||||
- Fixed IDs for Project menu items to allow them to be removed from the menu if needed.
|
||||
- Fixed an issue with remote application not terminating when IDE is closed while debugging is in progress.
|
||||
- Fixed refreshing a modified file when the editor is set to read-only mode.
|
||||
- Fixed saving/restoring configuration of 'Output'/'Console' tabs when IDE is closed while debugging is in progress.
|
||||
- Fixed removing variable name in Watch window after escaping editing.
|
||||
- Fixed #9 as it had incorrect logic in one of UTF filters.
|
||||
- Fixed edit menu shortcuts to work in the 'Output' window (when allowed).
|
||||
- Fixed reporting of processes that failed to start after 'Run' or 'Debug' commands.
|
||||
- Fixed executable path matching to work on systems that don't have file extensions.
|
||||
- Fixed #3 'unused parameter...' check not to fail on anonymous functions that are part of an expression.
|
||||
- Moved processing of `user.lua` to a later phase after tools and specs are already loaded to allow modification of IDE configuration from `user.lua`. Closes #5.
|
||||
- Added checks to prevent text modification in 'Output' and 'Console' windows. Fixes #8.
|
||||
- Disabled 'Run as Scratchpad' if there is no debugger registered capable of running it.
|
||||
- Disabled Stack and Watch updates when scratchpad is active as they interfere with application execution.
|
||||
|
||||
## v0.29 (May 31 2012)
|
||||
|
||||
### Highlights
|
||||
- Added **scratchpad** (running live) functionality.
|
||||
- Added **code analyzer** based on lua-inspect.
|
||||
- Updated **comment styling** to follow markdown syntax.
|
||||
|
||||
### Improvements
|
||||
- Added scratchpad (running live) functionality.
|
||||
- Added code analyzer based on lua-inspect.
|
||||
- Added Ctrl(-Shift)-TAB navigation between tabs in the editor.
|
||||
- Added navigation between editor tabs using Ctrl-PgUp and Ctrl-PgDn.
|
||||
- Added reporting of assignment to global variables in the code analyzer.
|
||||
- Added ability to turn external processes that connect to debugger into a scratchpad.
|
||||
- Added exit from full screen mode using ESC key.
|
||||
- Added reporting of compilation errors during debugging sessions.
|
||||
- Added handling of more errors in the shell to allow calculations like '(1+2)' to be executed correctly.
|
||||
- Added moving focus back to the notebook after unhiding/activating a wx window.
|
||||
- Added missing mime/code.dll and reorganized socket module files (socket.*) to load correctly with require.
|
||||
- Added stopping the debugger when a debugged program exits.
|
||||
- Added to static analysis reporting of unused parameters in functions.
|
||||
- Disabled warning in static analysis about unused 'self' in methods.
|
||||
- Removed 'error during pre-compilation' message from compile errors.
|
||||
- Updated comment styling to follow markdown syntax.
|
||||
|
||||
### Fixes
|
||||
- Fixed handling of scripts with comments in the remote shell.
|
||||
- Fixed an issue with Analyze process when the analyzed script has compilation errors.
|
||||
- Fixed an issue with scratchpad being on after Save dialog is canceled.
|
||||
- Fixed about screen.
|
||||
|
||||
## v0.28 (Mar 21 2012)
|
||||
|
||||
### Highlights
|
||||
- Added full screen mode.
|
||||
|
||||
### Improvements
|
||||
- Added option to activate output/console when Run/Debug/Compile commands are executed.
|
||||
- Added full screen mode.
|
||||
- Added killing a running process on IDE exit.
|
||||
- Added killing a running process with Shift-F12.
|
||||
- Disabled buffering of the output for scripts run from IDE.
|
||||
|
||||
### Fixes
|
||||
- Fixed 'Trace' command to continue working when a debugged file is not activated.
|
||||
- Fixed an issue with saving a file when no project directory is set.
|
||||
- Fixed missing semicolon in lualibs path; added path for debugger to search under lualibs.
|
||||
- Fixed an issue with a missing path separator, which prevented debugging from executing step commands in some cases.
|
||||
- Fixed missing slash on SaveAs by enforcing trailing slash for the project path.
|
||||
|
||||
## v0.27 (Feb 14 2012)
|
||||
|
||||
### Highlights
|
||||
- Added markup formatting in the comments.
|
||||
|
||||
### Improvements
|
||||
- Added markup formatting in the comments.
|
||||
- Added Debug and Run methods to simulate menu commands.
|
||||
- Added setting a project folder on initial start.
|
||||
- Added style processing for font name, font size, visibility and hotspot attributes.
|
||||
- Added setting the current project directory for the shell to allow 'require' commands to work with local modules.
|
||||
- Updated markup processing with run and debug commands, http link processing, and opening local files in a new window.
|
||||
- Enforced visibility for shell prompt.
|
||||
|
||||
### Fixes
|
||||
- Fixed activation of a correct tab when one of the editor tabs is closed.
|
||||
- Fixed an issue with file activation from a debugger.
|
||||
- Fixed the issue of ClosePage method being called with two different parameters.
|
||||
- Fixed the issue of the project dir being returned with two trailing slashes.
|
||||
- Fixed an issue with activating the currenly edited file in the file tree.
|
||||
- Wrapped DragAcceptFiles into a protected call to make it not fail on MacOS (compiled with wxwidgets 2.8.12).
|
||||
|
||||
## v0.26 (Jan 18 2012)
|
||||
@@ -71,13 +71,14 @@ ldexp = fn "build floating point number from x and the corresponding integral ex
|
||||
packUnorm2x16 = fn "Converts each comp. of v into 16-bit ints, packs results into the returned 32-bit uint. - (uint)(vec2 v)",
|
||||
packUnorm4x8 = fn "Converts each comp. of v into 8-bit ints, packs results into the returned 32-bit uint. - (uint)(vec4 v)",
|
||||
packSnorm4x8 = fn "Converts each comp. of v into 8-bit ints, packs results into the returned 32-bit uint. - (uint)(vec4 v)",
|
||||
packDouble2x32 = fn "Packs components of v into a 64-bit value and returns a double-prec value. - (double)(uvec2 v)",
|
||||
packHalf2x16 = fn "Converts each comp. of v into 16-bit half float, packs results into the returned 32-bit uint. - (uint)(vec2 v)",
|
||||
|
||||
unpackUnorm2x16 = fn "Unpacks 32-bit p into two 16-bit uints and converts them to normalized float. - (vec2)(uint p)",
|
||||
unpackUnorm4x8 = fn "Unpacks 32-bit p into four 8-bit uints and converts them to normalized float. - (vec4)(uint p)",
|
||||
unpackSnorm4x8 = fn "Unpacks 32-bit p into four 8-bit uints and converts them to normalized float. - (vec4)(uint p)",
|
||||
|
||||
packDouble2x32 = fn "Packs components of v into a 64-bit value and returns a double-prec value. - (double)(uvec2 v)",
|
||||
unpackDouble2x32 = fn "Returns a 2 component vector representation of v. - (uvec2)(double v)",
|
||||
unpackHalf2x16 = fn "Interprets p as two 16-bit half floats and returns them as vector. - (vec2)(uint p)",
|
||||
|
||||
length = fn "return scalar Euclidean length of a vector. - (type)(vecN)",
|
||||
distance = fn "return the Euclidean distance between two points. - (vecN)(vecN a, b)",
|
||||
@@ -135,6 +136,11 @@ EndPrimitive = fn "Completes current output primitive and starts a new one. - ()
|
||||
barrier = fn "Synchronizes across shader invocations. - ()()",
|
||||
|
||||
memoryBarrier = fn "control ordering of memory transactions issued by shader thread. - ()()",
|
||||
memoryBarrierAtomicCounter = fn "control ordering of memory transactions issued by shader thread. - ()()",
|
||||
memoryBarrierShared = fn "control ordering of memory transactions issued by shader thread. - ()()",
|
||||
memoryBarrierBuffer = fn "control ordering of memory transactions issued by shader thread. - ()()",
|
||||
memoryBarrierImage = fn "control ordering of memory transactions issued by shader thread. - ()()",
|
||||
groupMemoryBarrier = fn "control ordering of memory transactions issued by shader thread. - ()()",
|
||||
imageAtomicAdd = fn "performs atomic operation on individual texels returns new value. - (uint)(imageN, intN coord, [int sample], uint data)",
|
||||
imageAtomicMin = fn "performs atomic operation on individual texels returns new value. - (uint)(imageN, intN coord, [int sample], uint data)",
|
||||
imageAtomicMax = fn "performs atomic operation on individual texels returns new value. - (uint)(imageN, intN coord, [int sample], uint data)",
|
||||
@@ -167,41 +173,51 @@ texelFetchOffset = fn "integer coordinate lookup for a single texel with offset.
|
||||
}
|
||||
|
||||
local keyw =
|
||||
[[int uint half float bool double
|
||||
vec2 vec3 vec4 dvec2 dvec3 dvec4
|
||||
ivec2 ivec3 ivec4 uvec2 uvec3 uvec4 bvec2 bvec3 bvec4
|
||||
mat2 mat3 mat4 mat2x2 mat3x3 mat4x4 mat2x3 mat3x2 mat4x2 mat2x4 mat4x3 mat3x4
|
||||
dmat2 dmat3 dmat4 dmat2x2 dmat3x3 dmat4x4 dmat2x3 dmat3x2 dmat4x2 dmat2x4 dmat4x3 dmat3x4
|
||||
struct typedef void
|
||||
usampler1D usampler2D usampler3D usampler2DRect usamplerCube isampler1DArray usampler2DARRAY usamplerCubeArray usampler2DMS usampler2DMSArray
|
||||
isampler1D isampler2D isampler3D isampler2DRect isamplerCube isampler1DArray isampler2DARRAY isamplerCubeArray isampler2DMS isampler2DMSArray
|
||||
sampler1D sampler2D sampler3D sampler2DRect samplerCube sampler1DArray sampler2DArray samplerCubeArray sampler2DMS sampler2DMSArray
|
||||
sampler1DShadow sampler2DShadow sampler2DRectShadow sampler1DArrayShadow sampler2DArrayShadow samplerCubeArrayShadow
|
||||
usamplerBuffer isamplerBuffer samplerBuffer
|
||||
in out inout uniform const centroid sample attribute varying patch
|
||||
return switch case for do while if else break continue
|
||||
layout location vertices line_strip triangle_strip max_vertices stream
|
||||
triangles quads equal_spacing isolines fractional_even_spacing
|
||||
fractional_odd_spacing cw ccw point_mode lines_adjacency triangles_adjacency
|
||||
invocations
|
||||
origin_upper_left pixel_center_integer
|
||||
smooth flat noperspective highp mediump lowp shared packed std140 row_major column_major
|
||||
gl_FrontColor gl_BackColor gl_FrontSecondaryColor gl_BackSecondaryColor gl_Color gl_SecondaryColor
|
||||
subroutine gl_Position
|
||||
gl_VertexID gl_InstanceID gl_Normal gl_Vertex gl_MultiTexCoord0 gl_MultiTexCoord1
|
||||
gl_MultiTexCoord2 gl_MultiTexCoord3 gl_MultiTexCoord4 gl_MultiTexCoord5 gl_MultiTexCoord6
|
||||
gl_MultiTexCoord7 gl_FogCoord gl_PointSize gl_ClipDistance
|
||||
gl_TexCoord gl_FogFragCoord gl_ClipVertex gl_in
|
||||
gl_PatchVerticesIn
|
||||
gl_PrimitiveID gl_InvocationID gl_TessLevelOuter gl_TessLevelInner gl_TessCoord
|
||||
gl_InvocationID gl_PrimitiveIDIn gl_Layer gl_ViewportIndex gl_FrontFacing
|
||||
gl_PointCoord gl_SampleID gl_SamplePosition gl_FragColor
|
||||
gl_FragData gl_FragDepth gl_SampleMask
|
||||
[[ int uint half float bool double atomic_uint binding offset
|
||||
vec2 vec3 vec4 dvec2 dvec3 dvec4
|
||||
ivec2 ivec3 ivec4 uvec2 uvec3 uvec4 bvec2 bvec3 bvec4
|
||||
mat2 mat3 mat4 mat2x2 mat3x3 mat4x4 mat2x3 mat3x2 mat4x2 mat2x4 mat4x3 mat3x4
|
||||
dmat2 dmat3 dmat4 dmat2x2 dmat3x3 dmat4x4 dmat2x3 dmat3x2 dmat4x2 dmat2x4 dmat4x3 dmat3x4
|
||||
struct typedef void
|
||||
usampler1D usampler2D usampler3D usampler2DRect usamplerCube isampler1DArray usampler2DARRAY usamplerCubeArray usampler2DMS usampler2DMSArray
|
||||
isampler1D isampler2D isampler3D isampler2DRect isamplerCube isampler1DArray isampler2DARRAY isamplerCubeArray isampler2DMS isampler2DMSArray
|
||||
sampler1D sampler2D sampler3D sampler2DRect samplerCube sampler1DArray sampler2DArray samplerCubeArray sampler2DMS sampler2DMSArray
|
||||
sampler1DShadow sampler2DShadow sampler2DRectShadow sampler1DArrayShadow sampler2DArrayShadow samplerCubeArrayShadow
|
||||
usamplerBuffer isamplerBuffer samplerBuffer samplerRenderbuffer isamplerRenderbuffer usamplerRenderbuffer
|
||||
in out inout uniform const centroid sample attribute varying patch index true false
|
||||
return switch case for do while if else break continue main inline
|
||||
layout location vertices line_strip triangle_strip max_vertices stream
|
||||
triangles quads equal_spacing isolines fractional_even_spacing lines points
|
||||
fractional_odd_spacing cw ccw point_mode lines_adjacency triangles_adjacency
|
||||
invocations
|
||||
origin_upper_left pixel_center_integer depth_greater depth_greater depth_greater depth_unchanged
|
||||
smooth flat noperspective highp mediump lowp shared packed std140 std430 row_major column_major buffer
|
||||
gl_FrontColor gl_BackColor gl_FrontSecondaryColor gl_BackSecondaryColor gl_Color gl_SecondaryColor
|
||||
subroutine gl_Position gl_FragCoord
|
||||
gl_VertexID gl_InstanceID gl_Normal gl_Vertex gl_MultiTexCoord0 gl_MultiTexCoord1
|
||||
gl_MultiTexCoord2 gl_MultiTexCoord3 gl_MultiTexCoord4 gl_MultiTexCoord5 gl_MultiTexCoord6
|
||||
gl_MultiTexCoord7 gl_FogCoord gl_PointSize gl_ClipDistance
|
||||
gl_TexCoord gl_FogFragCoord gl_ClipVertex gl_in
|
||||
gl_PatchVerticesIn
|
||||
gl_PrimitiveID gl_InvocationID gl_TessLevelOuter gl_TessLevelInner gl_TessCoord
|
||||
gl_InvocationID gl_PrimitiveIDIn gl_Layer gl_ViewportIndex gl_FrontFacing
|
||||
gl_PointCoord gl_SampleID gl_SamplePosition gl_FragColor
|
||||
gl_FragData gl_FragDepth gl_SampleMask
|
||||
gl_NumWorkGroups gl_WorkGroupSize gl_WorkGroupID gl_LocalInvocationID gl_GlobalInvocationID gl_LocalInvocationIndex
|
||||
local_size_x local_size_y local_size_z
|
||||
|
||||
coherent volatile restrict readonly writeonly
|
||||
image1D image2D image3D image2DRect imageCube imageBuffer image1DArray image2DArray imageCubeArray image2DMS image2DMSArray
|
||||
uimage1D uimage2D uimage3D uimage2DRect uimageCube uimageBuffer uimage1DArray uimage2DArray uimageCubeArray uimage2DMS uimage2DMSArray
|
||||
iimage1D iimage2D iimage3D iimage2DRect iimageCube iimageBuffer iimage1DArray iimage2DArray iimageCubeArray iimage2DMS iimage2DMSArray
|
||||
size1x8 size1x16 size1x32 size2x32 size4x32 rgba32f rgba16f rg32f rg16f r32f r16f rgba8 rgba16 r11f_g11f_b10f rgb10_a2ui
|
||||
rgb10_a2i rg16 rg8 r16 r8 rgba32i rgba16i rgba8i rg32i rg16i rg8i r32i r16i r8i rgba32ui rgba16ui rgba8ui rg32ui rg16ui rg8ui
|
||||
r32ui r16ui r8ui rgba16_snorm rgba8_snorm rg16_snorm rg8_snorm r16_snorm r8_snorm
|
||||
]]
|
||||
|
||||
-- keywords - shouldn't be left out
|
||||
for w in keyw:gmatch("([a-zA-Z_0-9]+)") do
|
||||
api[w] = {type="keyword"}
|
||||
api[w] = {type="keyword"}
|
||||
end
|
||||
|
||||
return api
|
||||
|
||||
553
api/lua/anttweakbar.lua
Normal file
553
api/lua/anttweakbar.lua
Normal file
@@ -0,0 +1,553 @@
|
||||
--[[// tw tweakbar | AntTweakBar UI
|
||||
enum { TW_VERSION = 114 }
|
||||
|
||||
typedef enum ETwType {
|
||||
TW_TYPE_UNDEF,
|
||||
TW_TYPE_BOOLCPP,
|
||||
TW_TYPE_BOOL8,
|
||||
TW_TYPE_BOOL16,
|
||||
TW_TYPE_BOOL32,
|
||||
TW_TYPE_CHAR,
|
||||
TW_TYPE_INT8,
|
||||
TW_TYPE_UINT8,
|
||||
TW_TYPE_INT16,
|
||||
TW_TYPE_UINT16,
|
||||
TW_TYPE_INT32,
|
||||
TW_TYPE_UINT32,
|
||||
TW_TYPE_FLOAT,
|
||||
TW_TYPE_DOUBLE,
|
||||
TW_TYPE_COLOR32, // 32 bits color. Order is RGBA if API is OpenGL or Direct3D10, and inversed if API is Direct3D9 (can be modified by defining 'colorOrder=...', see doc)
|
||||
TW_TYPE_COLOR3F, // 3 floats color. Order is RGB.
|
||||
TW_TYPE_COLOR4F, // 4 floats color. Order is RGBA.
|
||||
TW_TYPE_CDSTRING, // Null-terminated C Dynamic String (pointer to an array of char dynamically allocated with malloc/realloc/strdup)
|
||||
TW_TYPE__TEMP1, //
|
||||
TW_TYPE_QUAT4F, // 4 floats encoding a quaternion {qx,qy,qz,qs}
|
||||
TW_TYPE_QUAT4D, // 4 doubles encoding a quaternion {qx,qy,qz,qs}
|
||||
TW_TYPE_DIR3F, // direction vector represented by 3 floats
|
||||
TW_TYPE_DIR3D, // direction vector represented by 3 doubles
|
||||
TW_TYPE_CSSTRING_LEN0 = 0x30000000,
|
||||
TW_TYPE_CSSTRING_LEN256 = 0x30000000 + 256,
|
||||
} TwType;
|
||||
|
||||
typedef struct CTwEnumVal {
|
||||
int Value;
|
||||
const char * Label;
|
||||
} TwEnumVal;
|
||||
|
||||
typedef struct CTwStructMember {
|
||||
const char * Name;
|
||||
TwType Type;
|
||||
size_t Offset;
|
||||
const char * DefString;
|
||||
} TwStructMember;
|
||||
|
||||
typedef enum ETwParamValueType {
|
||||
TW_PARAM_INT32,
|
||||
TW_PARAM_FLOAT,
|
||||
TW_PARAM_DOUBLE,
|
||||
TW_PARAM_CSTRING // Null-terminated array of char (ie, c-string)
|
||||
} TwParamValueType;
|
||||
|
||||
typedef enum ETwGraphAPI {
|
||||
TW_OPENGL = 1,
|
||||
TW_DIRECT3D9 = 2,
|
||||
TW_DIRECT3D10 = 3,
|
||||
TW_DIRECT3D11 = 4
|
||||
} TwGraphAPI;
|
||||
|
||||
typedef enum ETwKeyModifier {
|
||||
TW_KMOD_NONE = 0x0000, // same codes as SDL keysym.mod
|
||||
TW_KMOD_SHIFT = 0x0003,
|
||||
TW_KMOD_CTRL = 0x00c0,
|
||||
TW_KMOD_ALT = 0x0100,
|
||||
TW_KMOD_META = 0x0c00
|
||||
} TwKeyModifier;
|
||||
|
||||
typedef enum EKeySpecial {
|
||||
TW_KEY_BACKSPACE = '\b',
|
||||
TW_KEY_TAB = '\t',
|
||||
TW_KEY_CLEAR = 0x0c,
|
||||
TW_KEY_RETURN = '\r',
|
||||
TW_KEY_PAUSE = 0x13,
|
||||
TW_KEY_ESCAPE = 0x1b,
|
||||
TW_KEY_SPACE = ' ',
|
||||
TW_KEY_DELETE = 0x7f,
|
||||
TW_KEY_UP = 273,
|
||||
TW_KEY_DOWN,
|
||||
TW_KEY_RIGHT,
|
||||
TW_KEY_LEFT,
|
||||
TW_KEY_INSERT,
|
||||
TW_KEY_HOME,
|
||||
TW_KEY_END,
|
||||
TW_KEY_PAGE_UP,
|
||||
TW_KEY_PAGE_DOWN,
|
||||
TW_KEY_F1,
|
||||
TW_KEY_F2,
|
||||
TW_KEY_F3,
|
||||
TW_KEY_F4,
|
||||
TW_KEY_F5,
|
||||
TW_KEY_F6,
|
||||
TW_KEY_F7,
|
||||
TW_KEY_F8,
|
||||
TW_KEY_F9,
|
||||
TW_KEY_F10,
|
||||
TW_KEY_F11,
|
||||
TW_KEY_F12,
|
||||
TW_KEY_F13,
|
||||
TW_KEY_F14,
|
||||
TW_KEY_F15,
|
||||
TW_KEY_LAST
|
||||
} TwKeySpecial;
|
||||
|
||||
typedef enum ETwMouseAction {
|
||||
TW_MOUSE_RELEASED,
|
||||
TW_MOUSE_PRESSED
|
||||
} TwMouseAction;
|
||||
|
||||
typedef enum ETwMouseButtonID {
|
||||
TW_MOUSE_LEFT = 1,
|
||||
TW_MOUSE_MIDDLE = 2,
|
||||
TW_MOUSE_RIGHT = 3
|
||||
} TwMouseButtonID;
|
||||
|
||||
typedef void (*TwSetVarCallback) ( const void *value, void *clientData );
|
||||
typedef void (*TwGetVarCallback) ( void *value, void *clientData );
|
||||
typedef void (*TwButtonCallback) ( void *clientData );
|
||||
typedef void (*TwSummaryCallback) ( char *summaryString, size_t summaryMaxLength, const void *value, void *clientData );
|
||||
typedef void (*TwCopyCDStringToClient) ( char **destinationClientStringPtr, const char *sourceString );
|
||||
typedef void (*TwErrorHandler) ( const char *errorMessage );
|
||||
typedef void (*TwGLUTmousebuttonfun) ( int glutButton, int glutState, int mouseX, int mouseY );
|
||||
typedef void (*TwGLUTmousemotionfun) ( int mouseX, int mouseY );
|
||||
typedef void (*TwGLUTkeyboardfun) ( unsigned char glutKey, int mouseX, int mouseY );
|
||||
typedef void (*TwGLUTspecialfun) ( int glutKey, int mouseX, int mouseY );
|
||||
|
||||
typedef struct CTwBar TwBar;
|
||||
|
||||
TwBar* TwNewBar( const char *barName );
|
||||
int TwDeleteBar( TwBar *bar );
|
||||
int TwDeleteAllBars( );
|
||||
int TwSetTopBar( const TwBar *bar );
|
||||
TwBar* TwGetTopBar( );
|
||||
int TwSetBottomBar( const TwBar *bar );
|
||||
TwBar* TwGetBottomBar( );
|
||||
const char* TwGetBarName( TwBar *bar );
|
||||
int TwGetBarCount( );
|
||||
TwBar* TwGetBarByIndex( int barIndex );
|
||||
TwBar* TwGetBarByName( const char *barName );
|
||||
int TwRefreshBar( TwBar *bar );
|
||||
int TwAddVarRW( TwBar *bar, const char *name, TwType type, void *var, const char *def );
|
||||
int TwAddVarRO( TwBar *bar, const char *name, TwType type, const void *var, const char *def );
|
||||
int TwAddVarCB( TwBar *bar, const char *name, TwType type, TwSetVarCallback setCallback, TwGetVarCallback getCallback, void *clientData, const char *def );
|
||||
int TwAddButton( TwBar *bar, const char *name, TwButtonCallback callback, void *clientData, const char *def );
|
||||
int TwAddSeparator( TwBar *bar, const char *name, const char *def );
|
||||
int TwRemoveVar( TwBar *bar, const char *name );
|
||||
int TwRemoveAllVars( TwBar *bar );
|
||||
int TwDefine( const char *def );
|
||||
TwType TwDefineEnum( const char *name, const TwEnumVal *enumValues, unsigned int nbValues );
|
||||
TwType TwDefineEnumFromString( const char *name, const char *enumString );
|
||||
TwType TwDefineStruct( const char *name, const TwStructMember *structMembers, unsigned int nbMembers, size_t structSize, TwSummaryCallback summaryCallback, void *summaryClientData );
|
||||
void TwCopyCDStringToClientFunc( TwCopyCDStringToClient copyCDStringFunc );
|
||||
void TwCopyCDStringToLibrary( char **destinationLibraryStringPtr, const char *sourceClientString );
|
||||
int TwGetParam( TwBar *bar, const char *varName, const char *paramName, TwParamValueType paramValueType, unsigned int outValueMaxCount, void *outValues );
|
||||
int TwSetParam( TwBar *bar, const char *varName, const char *paramName, TwParamValueType paramValueType, unsigned int inValueCount, const void *inValues );
|
||||
int TwInit( TwGraphAPI graphAPI, void *device );
|
||||
int TwTerminate();
|
||||
int TwDraw();
|
||||
int TwWindowSize( int width, int height);
|
||||
int TwSetCurrentWindow( int windowID); // multi-windows support
|
||||
int TwGetCurrentWindow();
|
||||
int TwWindowExists( int windowID);
|
||||
int TwKeyPressed( int key, int modifiers);
|
||||
int TwKeyTest( int key, int modifiers);
|
||||
int TwMouseButton( TwMouseAction action, TwMouseButtonID button);
|
||||
int TwMouseMotion( int mouseX, int mouseY);
|
||||
int TwMouseWheel( int pos);
|
||||
const char* TwGetLastError( );
|
||||
void TwHandleErrors( TwErrorHandler errorHandler);
|
||||
int TwEventSDL( const void *sdlEvent, unsigned char sdlMajorVersion, unsigned char sdlMinorVersion);
|
||||
int TwEventSDL12( const void *sdlEvent);
|
||||
int TwEventSDL13( const void *sdlEvent);
|
||||
int TwEventMouseButtonGLFW( int glfwButton, int glfwAction );
|
||||
int TwEventKeyGLFW( int glfwKey, int glfwAction );
|
||||
int TwEventCharGLFW( int glfwChar, int glfwAction );
|
||||
int TwEventMouseButtonGLUT( int glutButton, int glutState, int mouseX, int mouseY);
|
||||
int TwEventMouseMotionGLUT( int mouseX, int mouseY);
|
||||
int TwEventKeyboardGLUT( unsigned char glutKey, int mouseX, int mouseY );
|
||||
int TwEventSpecialGLUT( int glutKey, int mouseX, int mouseY );
|
||||
int TwGLUTModifiersFunc( int (*glutGetModifiersFunc)(void) );
|
||||
int TwEventSFML( const void *sfmlEvent, unsigned char sfmlMajorVersion, unsigned char sfmlMinorVersion);
|
||||
]]
|
||||
--auto-generated api from ffi headers
|
||||
local api =
|
||||
{
|
||||
["TW_TYPE_UNDEF"] = { type ='value', },
|
||||
["TW_TYPE_BOOLCPP"] = { type ='value', },
|
||||
["TW_TYPE_BOOL8"] = { type ='value', },
|
||||
["TW_TYPE_BOOL16"] = { type ='value', },
|
||||
["TW_TYPE_BOOL32"] = { type ='value', },
|
||||
["TW_TYPE_CHAR"] = { type ='value', },
|
||||
["TW_TYPE_INT8"] = { type ='value', },
|
||||
["TW_TYPE_UINT8"] = { type ='value', },
|
||||
["TW_TYPE_INT16"] = { type ='value', },
|
||||
["TW_TYPE_UINT16"] = { type ='value', },
|
||||
["TW_TYPE_INT32"] = { type ='value', },
|
||||
["TW_TYPE_UINT32"] = { type ='value', },
|
||||
["TW_TYPE_FLOAT"] = { type ='value', },
|
||||
["TW_TYPE_DOUBLE"] = { type ='value', },
|
||||
["TW_TYPE_COLOR32"] = { type ='value', },
|
||||
["TW_TYPE_COLOR3F"] = { type ='value', },
|
||||
["TW_TYPE_COLOR4F"] = { type ='value', },
|
||||
["TW_TYPE_CDSTRING"] = { type ='value', },
|
||||
["TW_TYPE__TEMP1"] = { type ='value', },
|
||||
["TW_TYPE_QUAT4F"] = { type ='value', },
|
||||
["TW_TYPE_QUAT4D"] = { type ='value', },
|
||||
["TW_TYPE_DIR3F"] = { type ='value', },
|
||||
["TW_TYPE_DIR3D"] = { type ='value', },
|
||||
["TW_TYPE_CSSTRING_LEN0"] = { type ='value', },
|
||||
["TW_TYPE_CSSTRING_LEN256"] = { type ='value', },
|
||||
["TW_PARAM_INT32"] = { type ='value', },
|
||||
["TW_PARAM_FLOAT"] = { type ='value', },
|
||||
["TW_PARAM_DOUBLE"] = { type ='value', },
|
||||
["TW_PARAM_CSTRING"] = { type ='value', },
|
||||
["TW_OPENGL"] = { type ='value', },
|
||||
["TW_DIRECT3D9"] = { type ='value', },
|
||||
["TW_DIRECT3D10"] = { type ='value', },
|
||||
["TW_DIRECT3D11"] = { type ='value', },
|
||||
["TW_KMOD_NONE"] = { type ='value', },
|
||||
["TW_KMOD_SHIFT"] = { type ='value', },
|
||||
["TW_KMOD_CTRL"] = { type ='value', },
|
||||
["TW_KMOD_ALT"] = { type ='value', },
|
||||
["TW_KMOD_META"] = { type ='value', },
|
||||
["TW_KEY_BACKSPACE"] = { type ='value', },
|
||||
["TW_KEY_TAB"] = { type ='value', },
|
||||
["TW_KEY_CLEAR"] = { type ='value', },
|
||||
["TW_KEY_RETURN"] = { type ='value', },
|
||||
["TW_KEY_PAUSE"] = { type ='value', },
|
||||
["TW_KEY_ESCAPE"] = { type ='value', },
|
||||
["TW_KEY_SPACE"] = { type ='value', },
|
||||
["TW_KEY_DELETE"] = { type ='value', },
|
||||
["TW_KEY_UP"] = { type ='value', },
|
||||
["TW_KEY_DOWN"] = { type ='value', },
|
||||
["TW_KEY_RIGHT"] = { type ='value', },
|
||||
["TW_KEY_LEFT"] = { type ='value', },
|
||||
["TW_KEY_INSERT"] = { type ='value', },
|
||||
["TW_KEY_HOME"] = { type ='value', },
|
||||
["TW_KEY_END"] = { type ='value', },
|
||||
["TW_KEY_PAGE_UP"] = { type ='value', },
|
||||
["TW_KEY_PAGE_DOWN"] = { type ='value', },
|
||||
["TW_KEY_F1"] = { type ='value', },
|
||||
["TW_KEY_F2"] = { type ='value', },
|
||||
["TW_KEY_F3"] = { type ='value', },
|
||||
["TW_KEY_F4"] = { type ='value', },
|
||||
["TW_KEY_F5"] = { type ='value', },
|
||||
["TW_KEY_F6"] = { type ='value', },
|
||||
["TW_KEY_F7"] = { type ='value', },
|
||||
["TW_KEY_F8"] = { type ='value', },
|
||||
["TW_KEY_F9"] = { type ='value', },
|
||||
["TW_KEY_F10"] = { type ='value', },
|
||||
["TW_KEY_F11"] = { type ='value', },
|
||||
["TW_KEY_F12"] = { type ='value', },
|
||||
["TW_KEY_F13"] = { type ='value', },
|
||||
["TW_KEY_F14"] = { type ='value', },
|
||||
["TW_KEY_F15"] = { type ='value', },
|
||||
["TW_KEY_LAST"] = { type ='value', },
|
||||
["TW_MOUSE_RELEASED"] = { type ='value', },
|
||||
["TW_MOUSE_PRESSED"] = { type ='value', },
|
||||
["TW_MOUSE_LEFT"] = { type ='value', },
|
||||
["TW_MOUSE_MIDDLE"] = { type ='value', },
|
||||
["TW_MOUSE_RIGHT"] = { type ='value', },
|
||||
["TwNewBar"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(TwBar*)",
|
||||
valuetype = nil,
|
||||
args = "(const char *barName)", },
|
||||
["TwDeleteBar"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(int)",
|
||||
valuetype = nil,
|
||||
args = "(TwBar *bar)", },
|
||||
["TwDeleteAllBars"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(int)",
|
||||
valuetype = nil,
|
||||
args = "()", },
|
||||
["TwSetTopBar"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(int)",
|
||||
valuetype = nil,
|
||||
args = "(const TwBar *bar)", },
|
||||
["TwGetTopBar"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(TwBar*)",
|
||||
valuetype = nil,
|
||||
args = "()", },
|
||||
["TwSetBottomBar"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(int)",
|
||||
valuetype = nil,
|
||||
args = "(const TwBar *bar)", },
|
||||
["TwGetBottomBar"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(TwBar*)",
|
||||
valuetype = nil,
|
||||
args = "()", },
|
||||
["TwGetBarName"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(const char*)",
|
||||
valuetype = "string",
|
||||
args = "(TwBar *bar)", },
|
||||
["TwGetBarCount"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(int)",
|
||||
valuetype = nil,
|
||||
args = "()", },
|
||||
["TwGetBarByIndex"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(TwBar*)",
|
||||
valuetype = nil,
|
||||
args = "(int barIndex)", },
|
||||
["TwGetBarByName"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(TwBar*)",
|
||||
valuetype = nil,
|
||||
args = "(const char *barName)", },
|
||||
["TwRefreshBar"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(int)",
|
||||
valuetype = nil,
|
||||
args = "(TwBar *bar)", },
|
||||
["TwAddVarRW"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(int)",
|
||||
valuetype = nil,
|
||||
args = "(TwBar *bar, const char *name, TwType type, void *var, const char *def)", },
|
||||
["TwAddVarRO"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(int)",
|
||||
valuetype = nil,
|
||||
args = "(TwBar *bar, const char *name, TwType type, const void *var, const char *def)", },
|
||||
["TwAddVarCB"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(int)",
|
||||
valuetype = nil,
|
||||
args = "(TwBar *bar, const char *name, TwType type, TwSetVarCallback setCallback, TwGetVarCallback getCallback, void *clientData, const char *def)", },
|
||||
["TwAddButton"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(int)",
|
||||
valuetype = nil,
|
||||
args = "(TwBar *bar, const char *name, TwButtonCallback callback, void *clientData, const char *def)", },
|
||||
["TwAddSeparator"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(int)",
|
||||
valuetype = nil,
|
||||
args = "(TwBar *bar, const char *name, const char *def)", },
|
||||
["TwRemoveVar"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(int)",
|
||||
valuetype = nil,
|
||||
args = "(TwBar *bar, const char *name)", },
|
||||
["TwRemoveAllVars"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(int)",
|
||||
valuetype = nil,
|
||||
args = "(TwBar *bar)", },
|
||||
["TwDefine"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(int)",
|
||||
valuetype = nil,
|
||||
args = "(const char *def)", },
|
||||
["TwDefineEnum"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(TwType)",
|
||||
valuetype = nil,
|
||||
args = "(const char *name, const TwEnumVal *enumValues, unsigned int nbValues)", },
|
||||
["TwDefineEnumFromString"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(TwType)",
|
||||
valuetype = nil,
|
||||
args = "(const char *name, const char *enumString)", },
|
||||
["TwDefineStruct"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(TwType)",
|
||||
valuetype = nil,
|
||||
args = "(const char *name, const TwStructMember *structMembers, unsigned int nbMembers, size_t structSize, TwSummaryCallback summaryCallback, void *summaryClientData)", },
|
||||
["TwCopyCDStringToClientFunc"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(void)",
|
||||
valuetype = nil,
|
||||
args = "(TwCopyCDStringToClient copyCDStringFunc)", },
|
||||
["TwCopyCDStringToLibrary"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(void)",
|
||||
valuetype = nil,
|
||||
args = "(char **destinationLibraryStringPtr, const char *sourceClientString)", },
|
||||
["TwGetParam"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(int)",
|
||||
valuetype = nil,
|
||||
args = "(TwBar *bar, const char *varName, const char *paramName, TwParamValueType paramValueType, unsigned int outValueMaxCount, void *outValues)", },
|
||||
["TwSetParam"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(int)",
|
||||
valuetype = nil,
|
||||
args = "(TwBar *bar, const char *varName, const char *paramName, TwParamValueType paramValueType, unsigned int inValueCount, const void *inValues)", },
|
||||
["TwInit"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(int)",
|
||||
valuetype = nil,
|
||||
args = "(TwGraphAPI graphAPI, void *device)", },
|
||||
["TwTerminate"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(int)",
|
||||
valuetype = nil,
|
||||
args = "()", },
|
||||
["TwDraw"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(int)",
|
||||
valuetype = nil,
|
||||
args = "()", },
|
||||
["TwWindowSize"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(int)",
|
||||
valuetype = nil,
|
||||
args = "(int width, int height)", },
|
||||
["TwSetCurrentWindow"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(int)",
|
||||
valuetype = nil,
|
||||
args = "(int windowID)", },
|
||||
["TwGetCurrentWindow"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(int)",
|
||||
valuetype = nil,
|
||||
args = "()", },
|
||||
["TwWindowExists"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(int)",
|
||||
valuetype = nil,
|
||||
args = "(int windowID)", },
|
||||
["TwKeyPressed"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(int)",
|
||||
valuetype = nil,
|
||||
args = "(int key, int modifiers)", },
|
||||
["TwKeyTest"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(int)",
|
||||
valuetype = nil,
|
||||
args = "(int key, int modifiers)", },
|
||||
["TwMouseButton"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(int)",
|
||||
valuetype = nil,
|
||||
args = "(TwMouseAction action, TwMouseButtonID button)", },
|
||||
["TwMouseMotion"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(int)",
|
||||
valuetype = nil,
|
||||
args = "(int mouseX, int mouseY)", },
|
||||
["TwMouseWheel"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(int)",
|
||||
valuetype = nil,
|
||||
args = "(int pos)", },
|
||||
["TwGetLastError"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(const char*)",
|
||||
valuetype = "string",
|
||||
args = "()", },
|
||||
["TwHandleErrors"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(void)",
|
||||
valuetype = nil,
|
||||
args = "(TwErrorHandler errorHandler)", },
|
||||
["TwEventSDL"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(int)",
|
||||
valuetype = nil,
|
||||
args = "(const void *sdlEvent, unsigned char sdlMajorVersion, unsigned char sdlMinorVersion)", },
|
||||
["TwEventSDL12"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(int)",
|
||||
valuetype = nil,
|
||||
args = "(const void *sdlEvent)", },
|
||||
["TwEventSDL13"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(int)",
|
||||
valuetype = nil,
|
||||
args = "(const void *sdlEvent)", },
|
||||
["TwEventMouseButtonGLFW"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(int)",
|
||||
valuetype = nil,
|
||||
args = "(int glfwButton, int glfwAction)", },
|
||||
["TwEventKeyGLFW"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(int)",
|
||||
valuetype = nil,
|
||||
args = "(int glfwKey, int glfwAction)", },
|
||||
["TwEventCharGLFW"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(int)",
|
||||
valuetype = nil,
|
||||
args = "(int glfwChar, int glfwAction)", },
|
||||
["TwEventMouseButtonGLUT"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(int)",
|
||||
valuetype = nil,
|
||||
args = "(int glutButton, int glutState, int mouseX, int mouseY)", },
|
||||
["TwEventMouseMotionGLUT"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(int)",
|
||||
valuetype = nil,
|
||||
args = "(int mouseX, int mouseY)", },
|
||||
["TwEventKeyboardGLUT"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(int)",
|
||||
valuetype = nil,
|
||||
args = "(unsigned char glutKey, int mouseX, int mouseY)", },
|
||||
["TwEventSpecialGLUT"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(int)",
|
||||
valuetype = nil,
|
||||
args = "(int glutKey, int mouseX, int mouseY)", },
|
||||
["glutGetModifiersFunc"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(int)",
|
||||
valuetype = nil,
|
||||
args = "(void))", },
|
||||
["TwEventSFML"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(int)",
|
||||
valuetype = nil,
|
||||
args = "(const void *sfmlEvent, unsigned char sfmlMajorVersion, unsigned char sfmlMinorVersion)", },
|
||||
["TwEnumVal"] = { type ='class',
|
||||
description = "",
|
||||
childs = {
|
||||
["Value"] = { type ='value', description = "int ", valuetype = nil, },
|
||||
["Label"] = { type ='value', description = "const char * ", valuetype = "string", },
|
||||
}
|
||||
},
|
||||
["TwStructMember"] = { type ='class',
|
||||
description = "",
|
||||
childs = {
|
||||
["Name"] = { type ='value', description = "const char * ", valuetype = "string", },
|
||||
["Type"] = { type ='value', description = "TwType ", valuetype = nil, },
|
||||
["Offset"] = { type ='value', description = "size_t ", valuetype = nil, },
|
||||
["DefString"] = { type ='value', description = "const char * ", valuetype = "string", },
|
||||
}
|
||||
},
|
||||
}
|
||||
return {
|
||||
tw = {
|
||||
type = 'lib',
|
||||
description = "AntTweakBar UI",
|
||||
childs = api,
|
||||
},
|
||||
tweakbar = {
|
||||
type = 'lib',
|
||||
description = "AntTweakBar UI",
|
||||
childs = api,
|
||||
},
|
||||
}
|
||||
|
||||
26160
api/lua/glewgl.lua
26160
api/lua/glewgl.lua
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
bin/lua51.dll
Normal file
BIN
bin/lua51.dll
Normal file
Binary file not shown.
BIN
bin/winapi.dll
BIN
bin/winapi.dll
Binary file not shown.
BIN
bin/wx.dll
BIN
bin/wx.dll
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -4,7 +4,8 @@ Configuration files are loaded in the following order
|
||||
|
||||
1. <application>\config.lua
|
||||
2. cfg\user.lua
|
||||
3. -cfg commandline strings
|
||||
3. ~\.zbs\user.lua
|
||||
4. -cfg commandline strings
|
||||
|
||||
-- an example of how loaded configuration can be modified from this file
|
||||
|
||||
@@ -13,15 +14,22 @@ local luaspec = G.ide.specs['lua']
|
||||
luaspec.exts[2] = "luaz"
|
||||
luaspec.keywords[1] = luaspec.keywords[1] .. ' foo'
|
||||
|
||||
-- these changes are going to be mapped to ide.config.editor...
|
||||
-- change encoding to Cyrillic
|
||||
editor.fontencoding = G.wx.wxFONTENCODING_ISO8859_5
|
||||
-- or WinCyrillic
|
||||
editor.fontencoding = G.wx.wxFONTENCODING_CP1251
|
||||
outputshell.fontencoding = G.wx.wxFONTENCODING_CP1251
|
||||
-- change font size to 12
|
||||
editor.fontsize = 12 -- this is mapped to ide.config.editor.fontsize
|
||||
filehistorylength = 20 -- this is mapped to ide.config.filehistorylength
|
||||
|
||||
-- specify full path to love2d executable; this is only needed
|
||||
-- if the game folder and the executable are NOT in the same folder.
|
||||
path.love2d = 'd:/lua/love/love' -- set the path of love executable
|
||||
path.love2d = 'd:/lua/love/love'
|
||||
|
||||
-- specify full path to moai executable if it's not in one of PATH folders
|
||||
path.moai = 'd:/lua/moai/moai'
|
||||
|
||||
-- specify full path to lua interpreter if you need to use your own version
|
||||
path.lua = 'd:/lua/lua'
|
||||
|
||||
-- fix an issue with 0d0d0a line endings in MOAI examples,
|
||||
-- which may negatively affect breakpoints during debugging
|
||||
editor.iofilter = "0d0d0aFix"
|
||||
|
||||
--]]--
|
||||
|
||||
@@ -1,14 +1,38 @@
|
||||
local love2d
|
||||
local win = ide.osname == "Windows"
|
||||
|
||||
return {
|
||||
name = "Love2d",
|
||||
description = "Love2d game engine",
|
||||
api = {"baselib", "love2d"},
|
||||
frun = function(self,wfilename,rundebug)
|
||||
love2d = love2d or ide.config.path.love2d -- check if the path is configured
|
||||
if not love2d then
|
||||
local sep = win and ';' or ':'
|
||||
local path = (os.getenv('PATH') or '')..sep
|
||||
..(GetPathWithSep(self:fworkdir(wfilename)))..sep
|
||||
..(os.getenv('HOME') and GetPathWithSep(os.getenv('HOME'))..'bin' or '')
|
||||
local paths = {}
|
||||
for p in path:gmatch("[^"..sep.."]+") do
|
||||
love2d = love2d or GetFullPathIfExists(p, win and 'love.exe' or 'love')
|
||||
table.insert(paths, p)
|
||||
end
|
||||
if not love2d then
|
||||
DisplayOutput("Can't find love2d executable in any of the following folders: "
|
||||
..table.concat(paths, ", ").."\n")
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
if not GetFullPathIfExists(self:fworkdir(wfilename), 'main.lua') then
|
||||
DisplayOutput("Can't find 'main.lua' file in the current project folder.\n")
|
||||
return
|
||||
end
|
||||
|
||||
if rundebug then DebuggerAttachDefault() end
|
||||
local love2d = ide.config.path.love2d
|
||||
or wx.wxFileName(self:fprojdir(wfilename)):GetPath(wx.wxPATH_GET_VOLUME)
|
||||
.. '/love'
|
||||
local cmd = string.gsub(love2d, "\\","/") .. ' "' .. self:fprojdir(wfilename) .. '"'
|
||||
.. (rundebug and ' -debug' or '')
|
||||
|
||||
local cmd = ('"%s" "%s"%s'):format(love2d,
|
||||
self:fworkdir(wfilename), rundebug and ' -debug' or '')
|
||||
-- CommandLineRun(cmd,wdir,tooutput,nohide,stringcallback,uid,endcallback)
|
||||
return CommandLineRun(cmd,self:fworkdir(wfilename),true,false,nil,nil,
|
||||
function() ide.debugger.pid = nil end)
|
||||
@@ -16,12 +40,10 @@ return {
|
||||
fprojdir = function(self,wfilename)
|
||||
return wfilename:GetPath(wx.wxPATH_GET_VOLUME)
|
||||
end,
|
||||
fworkdir = function (self,wfilename)
|
||||
return ide.config.path.projectdir
|
||||
or wfilename:GetPath(wx.wxPATH_GET_VOLUME)
|
||||
fworkdir = function(self,wfilename)
|
||||
return ide.config.path.projectdir or wfilename:GetPath(wx.wxPATH_GET_VOLUME)
|
||||
end,
|
||||
hasdebugger = true,
|
||||
fattachdebug = function(self)
|
||||
DebuggerAttachDefault()
|
||||
end,
|
||||
fattachdebug = function(self) DebuggerAttachDefault() end,
|
||||
scratchextloop = true,
|
||||
}
|
||||
|
||||
@@ -1,23 +1,39 @@
|
||||
local exe
|
||||
|
||||
local function exePath()
|
||||
local mainpath = ide.editorFilename:gsub("[^/\\]+$","")
|
||||
local macExe = mainpath..'bin/lua.app/Contents/MacOS/lua'
|
||||
return ide.config.path.lua or
|
||||
(ide.osname == "Windows" and mainpath..[[bin\lua]]
|
||||
or (wx.wxFileExists(macExe) and macExe or mainpath..'bin/lua'))
|
||||
end
|
||||
|
||||
return {
|
||||
name = "Lua with Debugger",
|
||||
name = "Lua",
|
||||
description = "Lua interpreter with debugger",
|
||||
api = {"wxwidgets","baselib"},
|
||||
frun = function(self,wfilename,rundebug)
|
||||
local mainpath = string.gsub(ide.editorFilename:gsub("[^/\\]+$",""),"\\","/")
|
||||
local filepath = string.gsub(wfilename:GetFullPath(), "\\","/")
|
||||
exe = exe or exePath()
|
||||
local filepath = wfilename:GetFullPath()
|
||||
local script
|
||||
if rundebug then
|
||||
DebuggerAttachDefault()
|
||||
script = (
|
||||
"package.path=package.path..';"..mainpath.."lualibs/?/?.lua;"..mainpath.."lualibs/?.lua';"..
|
||||
"package.cpath=package.cpath..';"..mainpath.."bin/clibs/?.dll';"..
|
||||
rundebug
|
||||
)
|
||||
script = rundebug
|
||||
else
|
||||
script = ([[dofile '%s']]):format(filepath)
|
||||
-- if running on Windows and can't open the file, this may mean that
|
||||
-- the file path includes unicode characters that need special handling
|
||||
local fh = io.open(filepath, "r")
|
||||
if fh then fh:close() end
|
||||
if ide.osname == 'Windows' and pcall(require, "winapi")
|
||||
and wfilename:FileExists() and not fh then
|
||||
winapi.set_encoding(winapi.CP_UTF8)
|
||||
filepath = winapi.short_path(filepath)
|
||||
end
|
||||
|
||||
script = ('dofile [[%s]]'):format(filepath)
|
||||
end
|
||||
local code = ([[xpcall(function() io.stdout:setvbuf('no'); %s end,function(err) print(debug.traceback(err)) end)]]):format(script)
|
||||
local cmd = '"'..mainpath..'bin/lua" -e "'..code..'"'
|
||||
local cmd = '"'..exe..'" -e "'..code..'"'
|
||||
-- CommandLineRun(cmd,wdir,tooutput,nohide,stringcallback,uid,endcallback)
|
||||
return CommandLineRun(cmd,self:fworkdir(wfilename),true,false,nil,nil,
|
||||
function() ide.debugger.pid = nil end)
|
||||
@@ -26,11 +42,8 @@ return {
|
||||
return wfilename:GetPath(wx.wxPATH_GET_VOLUME)
|
||||
end,
|
||||
fworkdir = function (self,wfilename)
|
||||
return ide.config.path.projectdir
|
||||
or wfilename:GetPath(wx.wxPATH_GET_VOLUME)
|
||||
return ide.config.path.projectdir or wfilename:GetPath(wx.wxPATH_GET_VOLUME)
|
||||
end,
|
||||
hasdebugger = true,
|
||||
fattachdebug = function(self)
|
||||
DebuggerAttachDefault()
|
||||
end,
|
||||
fattachdebug = function(self) DebuggerAttachDefault() end,
|
||||
}
|
||||
|
||||
@@ -77,6 +77,7 @@ return {
|
||||
if not rundebug then
|
||||
local client = self:finitclient()
|
||||
ShellSupportRemote(client,self:fuid(wfilename))
|
||||
pid = nil
|
||||
end
|
||||
|
||||
return pid
|
||||
|
||||
85
interpreters/moai.lua
Normal file
85
interpreters/moai.lua
Normal file
@@ -0,0 +1,85 @@
|
||||
local moai
|
||||
local win = ide.osname == "Windows"
|
||||
|
||||
return {
|
||||
name = "Moai",
|
||||
description = "Moai mobile platform",
|
||||
api = {"baselib"},
|
||||
frun = function(self,wfilename,rundebug)
|
||||
moai = moai or ide.config.path.moai -- check if the path is configured
|
||||
if not moai then
|
||||
local sep = win and ';' or ':'
|
||||
local path = (os.getenv('PATH') or '')..sep
|
||||
..(os.getenv('MOAI_BIN') or '')..sep
|
||||
..(os.getenv('HOME') and os.getenv('HOME') .. '/bin' or '')
|
||||
local paths = {}
|
||||
for p in path:gmatch("[^"..sep.."]+") do
|
||||
moai = moai or GetFullPathIfExists(p, win and 'moai.exe' or 'moai')
|
||||
table.insert(paths, p)
|
||||
end
|
||||
if not moai then
|
||||
DisplayOutput("Can't find moai executable in any of the folders in PATH or MOAI_BIN: "
|
||||
..table.concat(paths, ", ").."\n")
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
local file
|
||||
local epoints = ide.config.moai and ide.config.moai.entrypoints
|
||||
if epoints then
|
||||
epoints = type(epoints) == 'table' and epoints or {epoints}
|
||||
for _,entry in pairs(epoints) do
|
||||
file = GetFullPathIfExists(self:fworkdir(wfilename), entry)
|
||||
if file then break end
|
||||
end
|
||||
if not file then
|
||||
DisplayOutput("Can't find any of the specified entry points ("
|
||||
..table.concat(epoints, ", ")
|
||||
..") in the current project; continuing with the current file...\n")
|
||||
end
|
||||
end
|
||||
|
||||
if rundebug then
|
||||
-- start running the application right away
|
||||
DebuggerAttachDefault({runstart=true, startwith = file})
|
||||
local code = (
|
||||
[[xpcall(function()
|
||||
io.stdout:setvbuf('no')
|
||||
require("mobdebug").moai() -- enable debugging for coroutines
|
||||
%s
|
||||
end, function(err) print(debug.traceback(err)) end)]]):format(rundebug)
|
||||
local tmpfile = wx.wxFileName()
|
||||
tmpfile:AssignTempFileName(".")
|
||||
file = tmpfile:GetFullPath()
|
||||
local f = io.open(file, "w")
|
||||
if not f then
|
||||
DisplayOutput("Can't open temporary file '"..file.."' for writing\n")
|
||||
return
|
||||
end
|
||||
f:write(code)
|
||||
f:close()
|
||||
end
|
||||
|
||||
file = file or wfilename:GetFullPath()
|
||||
|
||||
-- try to find a config file: (1) MOAI_CONFIG, (2) project directory,
|
||||
-- (3) folder with the current file, (4) folder with moai executable
|
||||
local config = GetFullPathIfExists(os.getenv('MOAI_CONFIG') or self:fworkdir(wfilename), 'config.lua')
|
||||
or GetFullPathIfExists(wfilename:GetPath(wx.wxPATH_GET_VOLUME), 'config.lua')
|
||||
or GetFullPathIfExists(wx.wxFileName(moai):GetPath(wx.wxPATH_GET_VOLUME), 'config.lua')
|
||||
local cmd = config and ('"%s" "%s" "%s"'):format(moai, config, file)
|
||||
or ('"%s" "%s"'):format(moai, file)
|
||||
-- CommandLineRun(cmd,wdir,tooutput,nohide,stringcallback,uid,endcallback)
|
||||
return CommandLineRun(cmd,self:fworkdir(wfilename),true,false,nil,nil,
|
||||
function() ide.debugger.pid = nil if rundebug then wx.wxRemoveFile(file) end end)
|
||||
end,
|
||||
fprojdir = function(self,wfilename)
|
||||
return wfilename:GetPath(wx.wxPATH_GET_VOLUME)
|
||||
end,
|
||||
fworkdir = function(self,wfilename)
|
||||
return ide.config.path.projectdir or wfilename:GetPath(wx.wxPATH_GET_VOLUME)
|
||||
end,
|
||||
hasdebugger = true,
|
||||
fattachdebug = function(self) DebuggerAttachDefault() end,
|
||||
scratchextloop = true,
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
--
|
||||
-- MobDebug 0.467
|
||||
-- MobDebug 0.489
|
||||
-- Copyright 2011-12 Paul Kulchenko
|
||||
-- Based on RemDebug 1.0 Copyright Kepler Project 2005
|
||||
--
|
||||
|
||||
local mobdebug = {
|
||||
_NAME = "mobdebug",
|
||||
_VERSION = 0.467,
|
||||
_VERSION = 0.489,
|
||||
_COPYRIGHT = "Paul Kulchenko",
|
||||
_DESCRIPTION = "Mobile Remote Debugger for the Lua programming language",
|
||||
port = 8171
|
||||
@@ -24,6 +24,8 @@ local setmetatable = setmetatable
|
||||
local string = string
|
||||
local tonumber = tonumber
|
||||
local mosync = mosync
|
||||
local jit = jit
|
||||
local moai = MOAISim
|
||||
|
||||
-- this is a socket class that implements maConnect interface
|
||||
local function socketMobileLua()
|
||||
@@ -188,7 +190,7 @@ local debugee = function ()
|
||||
end
|
||||
|
||||
local serpent = (function() ---- include Serpent module for serialization
|
||||
local n, v = "serpent", 0.15 -- (C) 2012 Paul Kulchenko; MIT License
|
||||
local n, v = "serpent", 0.16 -- (C) 2012 Paul Kulchenko; MIT License
|
||||
local c, d = "Paul Kulchenko", "Serializer and pretty printer of Lua data types"
|
||||
local snum = {[tostring(1/0)]='1/0 --[[math.huge]]',[tostring(-1/0)]='-1/0 --[[-math.huge]]',[tostring(0/0)]='0/0'}
|
||||
local badtype = {thread = true, userdata = true}
|
||||
@@ -213,7 +215,7 @@ local function s(t, opts)
|
||||
or ("%q"):format(s):gsub("\010","n"):gsub("\026","\\026") end
|
||||
local function comment(s,l) return comm and (l or 0) < comm and ' --[['..tostring(s)..']]' or '' end
|
||||
local function globerr(s,l) return globals[s] and globals[s]..comment(s,l) or not fatal
|
||||
and safestr(tostring(s))..comment('err',l) or error("Can't serialize "..tostring(s)) end
|
||||
and safestr(tostring(s)) or error("Can't serialize "..tostring(s)) end
|
||||
local function safename(path, name) -- generates foo.bar, foo[3], or foo['b a r']
|
||||
local n = name == nil and '' or name
|
||||
local plain = type(n) == "string" and n:match("^[%l%u_][%w_]*$") and not keyword[n]
|
||||
@@ -238,7 +240,7 @@ local function s(t, opts)
|
||||
elseif ttype == 'function' then
|
||||
seen[t] = spath
|
||||
local ok, res = pcall(string.dump, t)
|
||||
local func = ok and ((opts.nocode and "function() end" or
|
||||
local func = ok and ((opts.nocode and "function() --[[..skipped..]] end" or
|
||||
"loadstring("..safestr(res)..",'@serialized')")..comment(t, level))
|
||||
return tag..(func or globerr(t, level))
|
||||
elseif ttype == "table" then
|
||||
@@ -333,23 +335,52 @@ local function remove_breakpoint(file, line)
|
||||
end
|
||||
end
|
||||
|
||||
-- moai host uses full path in source files whereas the standard lua
|
||||
-- interpreter uses relative paths this debugger relies on.
|
||||
-- to check if there is a breakpoint, do a string search (from the end)
|
||||
-- to find a potentially matching breakpoint.
|
||||
-- may have false positives, but good enough as only affects moai debugging.
|
||||
local function has_breakpoint_moai(file, line)
|
||||
for fname, lines in pairs(breakpoints) do
|
||||
if #file > #fname and file:find('/'..fname, -#fname-1, true)
|
||||
and lines[line] then return true end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function has_breakpoint(file, line)
|
||||
return breakpoints[file] and breakpoints[file][line]
|
||||
or moai and has_breakpoint_moai(file, line)
|
||||
end
|
||||
|
||||
local function restore_vars(vars)
|
||||
if type(vars) ~= 'table' then return end
|
||||
local func = debug.getinfo(3, "f").func
|
||||
|
||||
-- locals need to be processed in the reverse order, starting from
|
||||
-- the inner block out, to make sure that the localized variables
|
||||
-- are correctly updated with only the closest variable with
|
||||
-- the same name being changed
|
||||
-- first loop find how many local variables there is, while
|
||||
-- the second loop processes them from i to 1
|
||||
local i = 1
|
||||
local written_vars = {}
|
||||
while true do
|
||||
local name = debug.getlocal(3, i)
|
||||
if not name then break end
|
||||
if string.sub(name, 1, 1) ~= '(' then debug.setlocal(3, i, vars[name]) end
|
||||
written_vars[name] = true
|
||||
i = i + 1
|
||||
end
|
||||
i = i - 1
|
||||
local written_vars = {}
|
||||
while i > 0 do
|
||||
local name = debug.getlocal(3, i)
|
||||
if not written_vars[name] then
|
||||
if string.sub(name, 1, 1) ~= '(' then debug.setlocal(3, i, vars[name]) end
|
||||
written_vars[name] = true
|
||||
end
|
||||
i = i - 1
|
||||
end
|
||||
|
||||
i = 1
|
||||
local func = debug.getinfo(3, "f").func
|
||||
while true do
|
||||
local name = debug.getupvalue(func, i)
|
||||
if not name then break end
|
||||
@@ -417,7 +448,7 @@ end
|
||||
local function debug_hook(event, line)
|
||||
if abort and is_safe(stack_level) then error(abort) end
|
||||
|
||||
-- LuaJIT needs special treatment. Because debug_hook is set for
|
||||
-- (1) LuaJIT needs special treatment. Because debug_hook is set for
|
||||
-- *all* coroutines, and not just the one being debugged as in regular Lua
|
||||
-- (http://lua-users.org/lists/lua-l/2011-06/msg00513.html),
|
||||
-- need to avoid debugging mobdebug's own code as LuaJIT doesn't
|
||||
@@ -427,7 +458,10 @@ local function debug_hook(event, line)
|
||||
-- 'tail return' events are not generated by LuaJIT).
|
||||
-- the next line checks if the debugger is run under LuaJIT and if
|
||||
-- one of debugger methods is present in the stack, it simply returns.
|
||||
if jit and in_debugger() then return end
|
||||
-- (2) also check if this debug hook has not been visited for any reason.
|
||||
-- this check is needed to avoid stepping in too early
|
||||
-- (for example, when coroutine.resume() is executed inside start()).
|
||||
if (jit or not seen_hook) and in_debugger() then return end
|
||||
|
||||
if event == "call" then
|
||||
stack_level = stack_level + 1
|
||||
@@ -442,13 +476,18 @@ local function debug_hook(event, line)
|
||||
skipcount = 0
|
||||
end
|
||||
|
||||
-- this is needed to check if the stack got shorter.
|
||||
-- this may happen when "pcall(load, '')" is called
|
||||
-- this is needed to check if the stack got shorter or longer.
|
||||
-- unfortunately counting call/return calls is not reliable.
|
||||
-- the discrepancy may happen when "pcall(load, '')" call is made
|
||||
-- or when "error()" is called in a function.
|
||||
-- in either case there are more "call" than "return" events reported.
|
||||
-- this validation is done for every "line" event, but should be
|
||||
-- "cheap" as it only checks for the stack to get shorter
|
||||
stack_level = stack_depth(stack_level)
|
||||
-- this validation is done for every "line" event, but should be "cheap"
|
||||
-- as it checks for the stack to get shorter (or longer by one call).
|
||||
-- start from one level higher just in case we need to grow the stack.
|
||||
-- this may happen after coroutine.resume call to a function that doesn't
|
||||
-- have any other instructions to execute. it triggers three returns:
|
||||
-- "return, tail return, return", which needs to be accounted for.
|
||||
stack_level = stack_depth(stack_level+1)
|
||||
local caller = debug.getinfo(2, "S")
|
||||
|
||||
-- grab the filename and fix it if needed
|
||||
@@ -467,46 +506,54 @@ local function debug_hook(event, line)
|
||||
lastfile = file
|
||||
end
|
||||
|
||||
local vars
|
||||
local vars, status, res
|
||||
if (watchescnt > 0) then
|
||||
vars = capture_vars()
|
||||
for index, value in pairs(watches) do
|
||||
setfenv(value, vars)
|
||||
local status, res = pcall(value)
|
||||
if status and res then
|
||||
coroutine.resume(coro_debugger, events.WATCH, vars, file, line, index)
|
||||
local ok, fired = pcall(value)
|
||||
if ok and fired then
|
||||
status, res = coroutine.resume(coro_debugger, events.WATCH, vars, file, line, index)
|
||||
break -- any one watch is enough; don't check multiple times
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if step_into
|
||||
or (step_over and stack_level <= step_level)
|
||||
or has_breakpoint(file, line)
|
||||
or (socket.select({server}, {}, 0))[server] then
|
||||
-- need to get into the "regular" debug handler, but only if there was
|
||||
-- no watch that was fired. If there was a watch, handle its result.
|
||||
local getin = (status == nil) and
|
||||
(step_into
|
||||
or (step_over and stack_level <= step_level)
|
||||
or has_breakpoint(file, line)
|
||||
or (socket.select({server}, {}, 0))[server])
|
||||
|
||||
if getin then
|
||||
vars = vars or capture_vars()
|
||||
seen_hook = true
|
||||
step_into = false
|
||||
step_over = false
|
||||
local status, res = coroutine.resume(coro_debugger, events.BREAK, vars, file, line)
|
||||
|
||||
-- handle 'stack' command that provides stack() information to the debugger
|
||||
if status and res == 'stack' then
|
||||
while status and res == 'stack' do
|
||||
-- resume with the stack trace and variables
|
||||
status, res = coroutine.resume(coro_debugger, events.STACK, stack(3), file, line)
|
||||
end
|
||||
end
|
||||
|
||||
-- need to recheck once more as resume after 'stack' command may
|
||||
-- return something else (for example, 'exit'), which needs to be handled
|
||||
if status and res and res ~= 'stack' then
|
||||
if abort == nil and res == "exit" then os.exit(1) end
|
||||
abort = res
|
||||
-- only abort if safe; if not, there is another (earlier) check inside
|
||||
-- debug_hook, which will abort execution at the first safe opportunity
|
||||
if is_safe(stack_level) then error(abort) end
|
||||
end -- abort execution if requested
|
||||
status, res = coroutine.resume(coro_debugger, events.BREAK, vars, file, line)
|
||||
end
|
||||
|
||||
-- handle 'stack' command that provides stack() information to the debugger
|
||||
if status and res == 'stack' then
|
||||
while status and res == 'stack' do
|
||||
-- resume with the stack trace and variables
|
||||
if vars then restore_vars(vars) end -- restore vars so they are reflected in stack values
|
||||
status, res = coroutine.resume(coro_debugger, events.STACK, stack(3), file, line)
|
||||
end
|
||||
end
|
||||
|
||||
-- need to recheck once more as resume after 'stack' command may
|
||||
-- return something else (for example, 'exit'), which needs to be handled
|
||||
if status and res and res ~= 'stack' then
|
||||
if abort == nil and res == "exit" then os.exit(1) end
|
||||
abort = res
|
||||
-- only abort if safe; if not, there is another (earlier) check inside
|
||||
-- debug_hook, which will abort execution at the first safe opportunity
|
||||
if is_safe(stack_level) then error(abort) end
|
||||
end
|
||||
|
||||
if vars then restore_vars(vars) end
|
||||
end
|
||||
end
|
||||
@@ -542,7 +589,8 @@ local function debugger_loop(sfile, sline)
|
||||
app = app or (wx and wx.wxGetApp and wx.wxGetApp())
|
||||
if app then
|
||||
local win = app:GetTopWindow()
|
||||
if win then
|
||||
local inloop = app:IsMainLoopRunning()
|
||||
if win and not inloop then
|
||||
-- process messages in a regular way
|
||||
-- and exit as soon as the event loop is idle
|
||||
win:Connect(wx.wxEVT_IDLE, function()
|
||||
@@ -559,7 +607,7 @@ local function debugger_loop(sfile, sline)
|
||||
if server.settimeout then server:settimeout() end -- back to blocking
|
||||
command = string.sub(line, string.find(line, "^[A-Z]+"))
|
||||
if command == "SETB" then
|
||||
local _, _, _, file, line = string.find(line, "^([A-Z]+)%s+([%w%p%s]+)%s+(%d+)%s*$")
|
||||
local _, _, _, file, line = string.find(line, "^([A-Z]+)%s+(.-)%s+(%d+)%s*$")
|
||||
if file and line then
|
||||
set_breakpoint(file, tonumber(line))
|
||||
server:send("200 OK\n")
|
||||
@@ -567,7 +615,7 @@ local function debugger_loop(sfile, sline)
|
||||
server:send("400 Bad Request\n")
|
||||
end
|
||||
elseif command == "DELB" then
|
||||
local _, _, _, file, line = string.find(line, "^([A-Z]+)%s+([%w%p%s]+)%s+(%d+)%s*$")
|
||||
local _, _, _, file, line = string.find(line, "^([A-Z]+)%s+(.-)%s+(%d+)%s*$")
|
||||
if file and line then
|
||||
remove_breakpoint(file, tonumber(line))
|
||||
server:send("200 OK\n")
|
||||
@@ -594,7 +642,7 @@ local function debugger_loop(sfile, sline)
|
||||
server:send("400 Bad Request\n")
|
||||
end
|
||||
elseif command == "LOAD" then
|
||||
local _, _, size, name = string.find(line, "^[A-Z]+%s+(%d+)%s+([%w%p%s]*[%w%p]+)%s*$")
|
||||
local _, _, size, name = string.find(line, "^[A-Z]+%s+(%d+)%s+(%S.-)%s*$")
|
||||
size = tonumber(size)
|
||||
|
||||
if abort == nil then -- no LOAD/RELOAD allowed inside start()
|
||||
@@ -634,14 +682,15 @@ local function debugger_loop(sfile, sline)
|
||||
elseif command == "SETW" then
|
||||
local _, _, exp = string.find(line, "^[A-Z]+%s+(.+)%s*$")
|
||||
if exp then
|
||||
local func = loadstring("return(" .. exp .. ")")
|
||||
local func, res = loadstring("return(" .. exp .. ")")
|
||||
if func then
|
||||
watchescnt = watchescnt + 1
|
||||
local newidx = #watches + 1
|
||||
watches[newidx] = func
|
||||
server:send("200 OK " .. newidx .. "\n")
|
||||
else
|
||||
server:send("400 Bad Request\n")
|
||||
server:send("401 Error in Expression " .. string.len(res) .. "\n")
|
||||
server:send(res)
|
||||
end
|
||||
else
|
||||
server:send("400 Bad Request\n")
|
||||
@@ -754,7 +803,12 @@ local function start(controller_host, controller_port)
|
||||
|
||||
server = socket.connect(controller_host, controller_port)
|
||||
if server then
|
||||
-- check if we are called from the debugger as this may happen
|
||||
-- when another debugger function calls start(); only check one level deep
|
||||
local this = debug.getinfo(1, "S").source
|
||||
local info = debug.getinfo(2, "Sl")
|
||||
if info.source == this then info = debug.getinfo(3, "Sl") end
|
||||
|
||||
local file = info.source
|
||||
if string.find(file, "@") == 1 then file = string.sub(file, 2) end
|
||||
if string.find(file, "%.[/\\]") == 1 then file = string.sub(file, 3) end
|
||||
@@ -765,14 +819,15 @@ local function start(controller_host, controller_port)
|
||||
-- start from 16th frame, which is sufficiently large for this check.
|
||||
stack_level = stack_depth(16)
|
||||
|
||||
debug.sethook(debug_hook, "lcr")
|
||||
coro_debugger = coroutine.create(debugger_loop)
|
||||
debug.sethook(debug_hook, "lcr")
|
||||
return coroutine.resume(coro_debugger, file, info.currentline)
|
||||
else
|
||||
print("Could not connect to " .. controller_host .. ":" .. controller_port)
|
||||
end
|
||||
end
|
||||
|
||||
local coro_debugee
|
||||
local function controller(controller_host, controller_port)
|
||||
-- only one debugging session can be run (as there is only one debug hook)
|
||||
if isrunning() then return end
|
||||
@@ -790,14 +845,15 @@ local function controller(controller_host, controller_port)
|
||||
return err
|
||||
end
|
||||
|
||||
seen_hook = true -- allow to accept all commands
|
||||
coro_debugger = coroutine.create(debugger_loop)
|
||||
|
||||
while true do
|
||||
step_into = true
|
||||
abort = false
|
||||
if skip then skipcount = skip end -- to force suspend right away
|
||||
while true do
|
||||
step_into = true -- start with step command
|
||||
abort = false -- reset abort flag from the previous loop
|
||||
if skip then skipcount = skip end -- force suspend right away
|
||||
|
||||
local coro_debugee = coroutine.create(debugee)
|
||||
coro_debugee = coroutine.create(debugee)
|
||||
debug.sethook(coro_debugee, debug_hook, "lcr")
|
||||
local status, err = coroutine.resume(coro_debugee)
|
||||
|
||||
@@ -819,7 +875,6 @@ local function controller(controller_host, controller_port)
|
||||
end
|
||||
end
|
||||
end
|
||||
server:close()
|
||||
else
|
||||
print("Could not connect to " .. controller_host .. ":" .. controller_port)
|
||||
return false
|
||||
@@ -837,7 +892,37 @@ local function loop(controller_host, controller_port)
|
||||
return controller(controller_host, controller_port)
|
||||
end
|
||||
|
||||
local coroutines = {}
|
||||
setmetatable(coroutines, {__mode = "k"}) -- "weak" keys
|
||||
|
||||
local function on()
|
||||
if not (isrunning() and server) then return end
|
||||
|
||||
local co = coroutine.running()
|
||||
if co then
|
||||
if not coroutines[co] then
|
||||
coroutines[co] = true
|
||||
debug.sethook(co, debug_hook, "lcr")
|
||||
end
|
||||
else
|
||||
debug.sethook(debug_hook, "lcr")
|
||||
end
|
||||
end
|
||||
|
||||
local function off()
|
||||
if not (isrunning() and server) then return end
|
||||
|
||||
local co = coroutine.running()
|
||||
if co then
|
||||
if coroutines[co] then coroutines[co] = false end
|
||||
debug.sethook(co)
|
||||
else
|
||||
debug.sethook()
|
||||
end
|
||||
end
|
||||
|
||||
local basedir = ""
|
||||
local function q(s) return s:gsub('([%(%)%.%%%+%-%*%?%[%^%$%]])','%%%1') end
|
||||
|
||||
-- Handles server debugging commands
|
||||
local function handle(params, client)
|
||||
@@ -857,12 +942,12 @@ local function handle(params, client)
|
||||
if status == "200" then
|
||||
-- don't need to do anything
|
||||
elseif status == "202" then
|
||||
_, _, file, line = string.find(breakpoint, "^202 Paused%s+([%w%p%s]+)%s+(%d+)%s*$")
|
||||
_, _, file, line = string.find(breakpoint, "^202 Paused%s+(.-)%s+(%d+)%s*$")
|
||||
if file and line then
|
||||
print("Paused at file " .. file .. " line " .. line)
|
||||
end
|
||||
elseif status == "203" then
|
||||
_, _, file, line, watch_idx = string.find(breakpoint, "^203 Paused%s+([%w%p%s]+)%s+(%d+)%s+(%d+)%s*$")
|
||||
_, _, file, line, watch_idx = string.find(breakpoint, "^203 Paused%s+(.-)%s+(%d+)%s+(%d+)%s*$")
|
||||
if file and line and watch_idx then
|
||||
print("Paused at file " .. file .. " line " .. line .. " (watch expression " .. watch_idx .. ": [" .. watches[watch_idx] .. "])")
|
||||
end
|
||||
@@ -881,10 +966,10 @@ local function handle(params, client)
|
||||
return nil, nil, "Debugger error: unexpected response '" .. breakpoint .. "'"
|
||||
end
|
||||
elseif command == "setb" then
|
||||
_, _, _, file, line = string.find(params, "^([a-z]+)%s+([%w%p%s]+)%s+(%d+)%s*$")
|
||||
_, _, _, file, line = string.find(params, "^([a-z]+)%s+(.-)%s+(%d+)%s*$")
|
||||
if file and line then
|
||||
file = string.gsub(file, "\\", "/") -- convert slash
|
||||
file = string.gsub(file, basedir, '') -- remove basedir
|
||||
file = string.gsub(file, q(basedir), '') -- remove basedir
|
||||
if not breakpoints[file] then breakpoints[file] = {} end
|
||||
client:send("SETB " .. file .. " " .. line .. "\n")
|
||||
if client:receive() == "200 OK" then
|
||||
@@ -905,16 +990,22 @@ local function handle(params, client)
|
||||
watches[watch_idx] = exp
|
||||
print("Inserted watch exp no. " .. watch_idx)
|
||||
else
|
||||
print("Error: Watch expression not inserted")
|
||||
local _, _, size = string.find(answer, "^401 Error in Expression (%d+)$")
|
||||
if size then
|
||||
local err = client:receive(tonumber(size)):gsub(".-:%d+:%s*","")
|
||||
print("Error: watch expression not set: " .. err)
|
||||
else
|
||||
print("Error: watch expression not set")
|
||||
end
|
||||
end
|
||||
else
|
||||
print("Invalid command")
|
||||
end
|
||||
elseif command == "delb" then
|
||||
_, _, _, file, line = string.find(params, "^([a-z]+)%s+([%w%p%s]+)%s+(%d+)%s*$")
|
||||
_, _, _, file, line = string.find(params, "^([a-z]+)%s+(.-)%s+(%d+)%s*$")
|
||||
if file and line then
|
||||
file = string.gsub(file, "\\", "/") -- convert slash
|
||||
file = string.gsub(file, basedir, '') -- remove basedir
|
||||
file = string.gsub(file, q(basedir), '') -- remove basedir
|
||||
if not breakpoints[file] then breakpoints[file] = {} end
|
||||
client:send("DELB " .. file .. " " .. line .. "\n")
|
||||
if client:receive() == "200 OK" then
|
||||
@@ -979,12 +1070,19 @@ local function handle(params, client)
|
||||
client:send(lines)
|
||||
else
|
||||
local file = io.open(exp, "r")
|
||||
if not file then print("Cannot open file " .. exp); return end
|
||||
local lines = file:read("*all")
|
||||
if not file and pcall(require, "winapi") then
|
||||
-- if file is not open and winapi is there, try with a short path;
|
||||
-- this may be needed for unicode paths on windows
|
||||
winapi.set_encoding(winapi.CP_UTF8)
|
||||
file = io.open(winapi.short_path(exp), "r")
|
||||
end
|
||||
if not file then error("Cannot open file " .. exp) end
|
||||
-- read the file and remove the shebang line as it causes a compilation error
|
||||
local lines = file:read("*all"):gsub("^#!.-\n", "\n")
|
||||
file:close()
|
||||
|
||||
local file = string.gsub(exp, "\\", "/") -- convert slash
|
||||
file = string.gsub(file, basedir, '') -- remove basedir
|
||||
file = string.gsub(file, q(basedir), '') -- remove basedir
|
||||
client:send("LOAD " .. string.len(lines) .. " " .. file .. "\n")
|
||||
client:send(lines)
|
||||
end
|
||||
@@ -992,7 +1090,7 @@ local function handle(params, client)
|
||||
if not params then
|
||||
return nil, nil, "Debugger error: missing response after EXEC/LOAD"
|
||||
end
|
||||
local _, _, status, len = string.find(params, "^(%d+)[%w%p%s]+%s+(%d+)%s*$")
|
||||
local _, _, status, len = string.find(params, "^(%d+).-%s+(%d+)%s*$")
|
||||
if status == "200" then
|
||||
len = tonumber(len)
|
||||
if len > 0 then
|
||||
@@ -1015,7 +1113,7 @@ local function handle(params, client)
|
||||
return res[1], res
|
||||
end
|
||||
elseif status == "201" then
|
||||
_, _, file, line = string.find(params, "^201 Started%s+([%w%p%s]+)%s+(%d+)%s*$")
|
||||
_, _, file, line = string.find(params, "^201 Started%s+(.-)%s+(%d+)%s*$")
|
||||
elseif status == "202" or params == "200 OK" then
|
||||
-- do nothing; this only happens when RE/LOAD command gets the response
|
||||
-- that was for the original command that was aborted
|
||||
@@ -1061,7 +1159,7 @@ local function handle(params, client)
|
||||
local src = string.gsub(frame[1][2], "\\", "/") -- convert slash
|
||||
if string.find(src, "@") == 1 then src = string.sub(src, 2) end
|
||||
if string.find(src, "%./") == 1 then src = string.sub(src, 3) end
|
||||
frame[1][2] = string.gsub(src, basedir, '') -- remove basedir
|
||||
frame[1][2] = string.gsub(src, q(basedir), '') -- remove basedir
|
||||
print(serpent.line(frame[1], {comment = false}))
|
||||
end
|
||||
return stack
|
||||
@@ -1130,7 +1228,7 @@ local function listen(host, port)
|
||||
client:receive()
|
||||
|
||||
local breakpoint = client:receive()
|
||||
local _, _, file, line = string.find(breakpoint, "^202 Paused%s+([%w%p%s]+)%s+(%d+)%s*$")
|
||||
local _, _, file, line = string.find(breakpoint, "^202 Paused%s+(.-)%s+(%d+)%s*$")
|
||||
if file and line then
|
||||
print("Paused at file " .. file )
|
||||
print("Type 'help' for commands")
|
||||
@@ -1149,6 +1247,37 @@ local function listen(host, port)
|
||||
end
|
||||
end
|
||||
|
||||
local cocreate
|
||||
local function coro()
|
||||
if cocreate then return end -- only set once
|
||||
cocreate = cocreate or coroutine.create
|
||||
coroutine.create = function(f, ...)
|
||||
return cocreate(function(...)
|
||||
require("mobdebug").on()
|
||||
return f(...)
|
||||
end, ...)
|
||||
end
|
||||
end
|
||||
|
||||
local moconew
|
||||
local function moai()
|
||||
if moconew then return end -- only set once
|
||||
moconew = moconew or (MOAICoroutine and MOAICoroutine.new)
|
||||
if not moconew then return end
|
||||
MOAICoroutine.new = function(...)
|
||||
local thread = moconew(...)
|
||||
local mt = getmetatable(thread)
|
||||
local patched = mt.run
|
||||
mt.run = function(self, f, ...)
|
||||
return patched(self, function(...)
|
||||
require("mobdebug").on()
|
||||
return f(...)
|
||||
end, ...)
|
||||
end
|
||||
return thread
|
||||
end
|
||||
end
|
||||
|
||||
-- make public functions available
|
||||
mobdebug.listen = listen
|
||||
mobdebug.loop = loop
|
||||
@@ -1156,6 +1285,10 @@ mobdebug.scratchpad = scratchpad
|
||||
mobdebug.handle = handle
|
||||
mobdebug.connect = connect
|
||||
mobdebug.start = start
|
||||
mobdebug.on = on
|
||||
mobdebug.off = off
|
||||
mobdebug.moai = moai
|
||||
mobdebug.coro = coro
|
||||
mobdebug.line = serpent.line
|
||||
mobdebug.dump = serpent.dump
|
||||
|
||||
|
||||
315
lualibs/testwell.lua
Normal file
315
lualibs/testwell.lua
Normal file
@@ -0,0 +1,315 @@
|
||||
--
|
||||
-- Copyright (C) 2012 Paul Kulchenko
|
||||
-- A simple testing library
|
||||
-- Based on lua-TestMore : <http://fperrad.github.com/lua-TestMore/>
|
||||
-- Copyright (c) 2009-2011 Francois Perrad
|
||||
-- This library is licensed under the terms of the MIT/X11 license,
|
||||
-- like Lua itself.
|
||||
--
|
||||
|
||||
local pairs = pairs
|
||||
local tostring = tostring
|
||||
local type = type
|
||||
local _G = _G or _ENV
|
||||
|
||||
-----------------------------------------------------------
|
||||
|
||||
local tb = {
|
||||
curr_test = 0,
|
||||
good_test = 0,
|
||||
skip_test = 0,
|
||||
}
|
||||
|
||||
function tb:print(...)
|
||||
print(...)
|
||||
end
|
||||
|
||||
function tb:note(...)
|
||||
self:print(...)
|
||||
end
|
||||
|
||||
function tb:diag(...)
|
||||
local arg = {...}
|
||||
for k, v in pairs(arg) do
|
||||
arg[k] = tostring(v)
|
||||
end
|
||||
local msg = table.concat(arg)
|
||||
msg = msg:gsub("\n", "\n# ")
|
||||
msg = msg:gsub("\n# \n", "\n#\n")
|
||||
msg = msg:gsub("\n# $", '')
|
||||
self:print("# " .. msg)
|
||||
end
|
||||
|
||||
function tb:ok(test, name, more)
|
||||
self.curr_test = self.curr_test + 1
|
||||
self.good_test = self.good_test + (test and 1 or 0)
|
||||
self.skip_test = self.skip_test + (test == nil and 1 or 0)
|
||||
name = tostring(name or '')
|
||||
local out = ''
|
||||
if not test then
|
||||
out = "not "
|
||||
end
|
||||
out = out .. "ok " .. self.curr_test
|
||||
if name ~= '' then
|
||||
out = out .. " - " .. name
|
||||
end
|
||||
self:print(out)
|
||||
if test == false then
|
||||
self:diag(" Failed test " .. (name and ("'" .. name .. "'") or ''))
|
||||
if debug then
|
||||
local info = debug.getinfo(3)
|
||||
local file = info.short_src
|
||||
local line = info.currentline
|
||||
self:diag(" in " .. file .. " at line " .. line .. ".")
|
||||
end
|
||||
self:diag(more)
|
||||
end
|
||||
end
|
||||
|
||||
function tb:done_testing(reset)
|
||||
local c, g, s = self.curr_test, self.good_test, self.skip_test
|
||||
if reset then
|
||||
self.curr_test = 0
|
||||
self.good_test = 0
|
||||
self.skip_test = 0
|
||||
end
|
||||
return c, g, s
|
||||
end
|
||||
|
||||
-----------------------------------------------------------
|
||||
|
||||
local serpent = (function() ---- include Serpent module for serialization
|
||||
local n, v = "serpent", 0.15 -- (C) 2012 Paul Kulchenko; MIT License
|
||||
local c, d = "Paul Kulchenko", "Serializer and pretty printer of Lua data types"
|
||||
local snum = {[tostring(1/0)]='1/0 --[[math.huge]]',[tostring(-1/0)]='-1/0 --[[-math.huge]]',[tostring(0/0)]='0/0'}
|
||||
local badtype = {thread = true, userdata = true}
|
||||
local keyword, globals, G = {}, {}, (_G or _ENV)
|
||||
for _,k in ipairs({'and', 'break', 'do', 'else', 'elseif', 'end', 'false',
|
||||
'for', 'function', 'goto', 'if', 'in', 'local', 'nil', 'not', 'or', 'repeat',
|
||||
'return', 'then', 'true', 'until', 'while'}) do keyword[k] = true end
|
||||
for k,v in pairs(G) do globals[v] = k end -- build func to name mapping
|
||||
for _,g in ipairs({'coroutine', 'debug', 'io', 'math', 'string', 'table', 'os'}) do
|
||||
for k,v in pairs(G[g]) do globals[v] = g..'.'..k end end
|
||||
|
||||
local function s(t, opts)
|
||||
local name, indent, fatal = opts.name, opts.indent, opts.fatal
|
||||
local sparse, custom, huge = opts.sparse, opts.custom, not opts.nohuge
|
||||
local space, maxl = (opts.compact and '' or ' '), (opts.maxlevel or math.huge)
|
||||
local comm = opts.comment and (tonumber(opts.comment) or math.huge)
|
||||
local seen, sref, syms, symn = {}, {}, {}, 0
|
||||
local function gensym(val) return tostring(val):gsub("[^%w]",""):gsub("(%d%w+)",
|
||||
function(s) if not syms[s] then symn = symn+1; syms[s] = symn end return syms[s] end) end
|
||||
local function safestr(s) return type(s) == "number" and (huge and snum[tostring(s)] or s)
|
||||
or type(s) ~= "string" and tostring(s) -- escape NEWLINE/010 and EOF/026
|
||||
or ("%q"):format(s):gsub("\010","n"):gsub("\026","\\026") end
|
||||
local function comment(s,l) return comm and (l or 0) < comm and ' --[['..tostring(s)..']]' or '' end
|
||||
local function globerr(s,l) return globals[s] and globals[s]..comment(s,l) or not fatal
|
||||
and safestr(tostring(s))..comment('err',l) or error("Can't serialize "..tostring(s)) end
|
||||
local function safename(path, name) -- generates foo.bar, foo[3], or foo['b a r']
|
||||
local n = name == nil and '' or name
|
||||
local plain = type(n) == "string" and n:match("^[%l%u_][%w_]*$") and not keyword[n]
|
||||
local safe = plain and n or '['..safestr(n)..']'
|
||||
return (path or '')..(plain and path and '.' or '')..safe, safe end
|
||||
local alphanumsort = type(opts.sortkeys) == 'function' and opts.sortkeys or function(o, n)
|
||||
local maxn, to = tonumber(n) or 12, {number = 'a', string = 'b'}
|
||||
local function padnum(d) return ("%0"..maxn.."d"):format(d) end
|
||||
table.sort(o, function(a,b)
|
||||
return (o[a] and 0 or to[type(a)] or 'z')..(tostring(a):gsub("%d+",padnum))
|
||||
< (o[b] and 0 or to[type(b)] or 'z')..(tostring(b):gsub("%d+",padnum)) end) end
|
||||
local function val2str(t, name, indent, path, plainindex, level)
|
||||
local ttype, level = type(t), (level or 0)
|
||||
local spath, sname = safename(path, name)
|
||||
local tag = plainindex and
|
||||
((type(name) == "number") and '' or name..space..'='..space) or
|
||||
(name ~= nil and sname..space..'='..space or '')
|
||||
if seen[t] then
|
||||
table.insert(sref, spath..space..'='..space..seen[t])
|
||||
return tag..'nil'..comment('ref', level)
|
||||
elseif badtype[ttype] then return tag..globerr(t, level)
|
||||
elseif ttype == 'function' then
|
||||
seen[t] = spath
|
||||
local ok, res = pcall(string.dump, t)
|
||||
local func = ok and ((opts.nocode and "function() end" or
|
||||
"loadstring("..safestr(res)..",'@serialized')")..comment(t, level))
|
||||
return tag..(func or globerr(t, level))
|
||||
elseif ttype == "table" then
|
||||
if level >= maxl then return tag..'{}'..comment('max', level) end
|
||||
seen[t] = spath
|
||||
if next(t) == nil then return tag..'{}'..comment(t, level) end -- table empty
|
||||
local maxn, o, out = #t, {}, {}
|
||||
for key = 1, maxn do table.insert(o, key) end
|
||||
for key in pairs(t) do if not o[key] then table.insert(o, key) end end
|
||||
if opts.sortkeys then alphanumsort(o, opts.sortkeys) end
|
||||
for n, key in ipairs(o) do
|
||||
local value, ktype, plainindex = t[key], type(key), n <= maxn and not sparse
|
||||
if opts.ignore and opts.ignore[value] -- skip ignored values; do nothing
|
||||
or sparse and value == nil then -- skipping nils; do nothing
|
||||
elseif ktype == 'table' or ktype == 'function' then
|
||||
if not seen[key] and not globals[key] then
|
||||
table.insert(sref, 'local '..val2str(key,gensym(key),indent)) end
|
||||
table.insert(sref, seen[t]..'['..(seen[key] or globals[key] or gensym(key))
|
||||
..']'..space..'='..space..(seen[value] or val2str(value,nil,indent)))
|
||||
else
|
||||
if badtype[ktype] then plainindex, key = true, '['..globerr(key, level+1)..']' end
|
||||
table.insert(out,val2str(value,key,indent,spath,plainindex,level+1))
|
||||
end
|
||||
end
|
||||
local prefix = string.rep(indent or '', level)
|
||||
local head = indent and '{\n'..prefix..indent or '{'
|
||||
local body = table.concat(out, ','..(indent and '\n'..prefix..indent or space))
|
||||
local tail = indent and "\n"..prefix..'}' or '}'
|
||||
return (custom and custom(tag,head,body,tail) or tag..head..body..tail)..comment(t, level)
|
||||
else return tag..safestr(t) end -- handle all other types
|
||||
end
|
||||
local sepr = indent and "\n" or ";"..space
|
||||
local body = val2str(t, name, indent) -- this call also populates sref
|
||||
local tail = #sref>0 and table.concat(sref, sepr)..sepr or ''
|
||||
return not name and body or "do local "..body..sepr..tail.."return "..name..sepr.."end"
|
||||
end
|
||||
|
||||
local function merge(a, b) if b then for k,v in pairs(b) do a[k] = v end end; return a; end
|
||||
return { _NAME = n, _COPYRIGHT = c, _DESCRIPTION = d, _VERSION = v, serialize = s,
|
||||
dump = function(a, opts) return s(a, merge({name = '_', compact = true, sparse = true}, opts)) end,
|
||||
line = function(a, opts) return s(a, merge({sortkeys = true, comment = true}, opts)) end,
|
||||
block = function(a, opts) return s(a, merge({indent = ' ', sortkeys = true, comment = true}, opts)) end }
|
||||
end)() ---- end of Serpent module
|
||||
|
||||
-----------------------------------------------------------
|
||||
|
||||
local m = {}
|
||||
|
||||
function m.ok(test, name)
|
||||
tb:ok(test, name)
|
||||
end
|
||||
|
||||
local parms = {comment = false}
|
||||
function m.is(got, expected, name)
|
||||
local tgot, texp = type(got), type(expected)
|
||||
local vgot, vexp = serpent.line(got, parms), serpent.line(expected, parms)
|
||||
local pass = vgot == vexp
|
||||
if got == nil then pass = nil end
|
||||
tb:ok(pass, name, not pass and
|
||||
" got: " .. vgot .. " (" .. tgot .. ")" ..
|
||||
"\n expected: " .. vexp .. " (" .. texp .. ")")
|
||||
end
|
||||
|
||||
function m.isnt(got, expected, name)
|
||||
local tgot, texp = type(got), type(expected)
|
||||
local vgot, vexp = serpent.line(got, parms), serpent.line(expected, parms)
|
||||
local pass = vgot ~= vexp
|
||||
if got == nil then pass = nil end
|
||||
tb:ok(pass, name, not pass and
|
||||
" got: " .. vgot .. " (" .. tgot .. ")" ..
|
||||
"\n expected: anything else")
|
||||
end
|
||||
|
||||
function m.like(got, pattern, name)
|
||||
if type(pattern) ~= 'string' then
|
||||
return tb:ok(false, name, "pattern isn't a string : " .. tostring(pattern))
|
||||
end
|
||||
|
||||
local pass = tostring(got):match(pattern)
|
||||
if got == nil then pass = nil end
|
||||
tb:ok(pass, name, not pass and
|
||||
" '" .. tostring(got) .. "'" ..
|
||||
"\n doesn't match '" .. pattern .. "'")
|
||||
end
|
||||
|
||||
function m.unlike(got, pattern, name)
|
||||
if type(pattern) ~= 'string' then
|
||||
return tb:ok(false, name, "pattern isn't a string : " .. tostring(pattern))
|
||||
end
|
||||
|
||||
local pass = not tostring(got):match(pattern)
|
||||
if got == nil then pass = nil end
|
||||
tb:ok(pass, name, not pass and
|
||||
" '" .. tostring(got) .. "'" ..
|
||||
"\n matches '" .. pattern .. "'")
|
||||
end
|
||||
|
||||
local cmp = {
|
||||
['<'] = function (a, b) return a < b end,
|
||||
['<='] = function (a, b) return a <= b end,
|
||||
['>'] = function (a, b) return a > b end,
|
||||
['>='] = function (a, b) return a >= b end,
|
||||
['=='] = function (a, b) return a == b end,
|
||||
['~='] = function (a, b) return a ~= b end,
|
||||
}
|
||||
|
||||
function m.cmp_ok(this, op, that, name)
|
||||
local f = cmp[op]
|
||||
if not f then
|
||||
return tb:ok(false, name, "unknown operator : " .. tostring(op))
|
||||
end
|
||||
|
||||
local pass = f(this, that)
|
||||
if this == nil then pass = nil end
|
||||
tb:ok(pass, name, not pass and
|
||||
" " .. tostring(this) ..
|
||||
"\n " .. op ..
|
||||
"\n " .. tostring(that))
|
||||
end
|
||||
|
||||
function m.type_ok(val, t, name)
|
||||
if type(t) ~= 'string' then
|
||||
return tb:ok(false, name, "type isn't a string : " .. tostring(t))
|
||||
end
|
||||
|
||||
if type(val) == t then
|
||||
tb:ok(true, name)
|
||||
else
|
||||
tb:ok(false, name,
|
||||
" " .. tostring(val) .. " isn't a '" .. t .."', it's a '" .. type(val) .. "'")
|
||||
end
|
||||
end
|
||||
|
||||
function m.diag(...)
|
||||
tb:diag(...)
|
||||
end
|
||||
|
||||
function m.report()
|
||||
local total, good, skipped = tb:done_testing(true)
|
||||
if total == 0 then return end
|
||||
local failed = total - good - skipped
|
||||
local sum = ("(%d/%d/%d)."):format(good, skipped, total)
|
||||
local num, msg = 0, ""
|
||||
if good > 0 then
|
||||
num, msg = good, msg .. "passed " .. good
|
||||
end
|
||||
if failed > 0 then
|
||||
num, msg = failed, msg .. (#msg > 0 and (skipped > 0 and ", " or " and ") or "")
|
||||
.. "failed " .. failed
|
||||
end
|
||||
if skipped > 0 then
|
||||
num, msg = skipped, msg .. (#msg > 0 and ((good > 0 and failed > 0 and ',' or '') .." and ") or "")
|
||||
.. "skipped " .. skipped
|
||||
end
|
||||
msg = ("Looks like you %s test%s of %d %s"):format(msg, (num > 1 and 's' or ''), total, sum)
|
||||
if skipped == total then msg = "Looks like you skipped all tests " .. sum end
|
||||
if good == total then msg = "All tests passed " .. sum end
|
||||
tb:note(("1..%d # %s"):format(total, msg))
|
||||
end
|
||||
|
||||
function m.ismain()
|
||||
for l = 3, 64 do -- only check up to 64 level; no more needed
|
||||
local info = debug.getinfo(l)
|
||||
if not info then return true end
|
||||
if info.func == require then return false end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
-- this is needed to call report() when the test object is destroyed
|
||||
if _VERSION >= "Lua 5.2" then
|
||||
setmetatable(m, {__gc = m.report})
|
||||
else
|
||||
-- keep sentinel alive until 'm' is garbage collected
|
||||
m.sentinel = newproxy(true)
|
||||
getmetatable(m.sentinel).__gc = m.report
|
||||
end
|
||||
|
||||
for k, v in pairs(m) do -- injection
|
||||
_G[k] = v
|
||||
end
|
||||
|
||||
return m
|
||||
@@ -46,7 +46,7 @@ return {
|
||||
},
|
||||
|
||||
keywords = {
|
||||
[[int uint half float bool double
|
||||
[[int uint half float bool double atomic_uint binding offset
|
||||
vec2 vec3 vec4 dvec2 dvec3 dvec4
|
||||
ivec2 ivec3 ivec4 uvec2 uvec3 uvec4 bvec2 bvec3 bvec4
|
||||
mat2 mat3 mat4 mat2x2 mat3x3 mat4x4 mat2x3 mat3x2 mat4x2 mat2x4 mat4x3 mat3x4
|
||||
@@ -63,8 +63,8 @@ return {
|
||||
triangles quads equal_spacing isolines fractional_even_spacing lines points
|
||||
fractional_odd_spacing cw ccw point_mode lines_adjacency triangles_adjacency
|
||||
invocations
|
||||
origin_upper_left pixel_center_integer
|
||||
smooth flat noperspective highp mediump lowp shared packed std140 row_major column_major
|
||||
origin_upper_left pixel_center_integer depth_greater depth_greater depth_greater depth_unchanged
|
||||
smooth flat noperspective highp mediump lowp shared packed std140 std430 row_major column_major buffer
|
||||
gl_FrontColor gl_BackColor gl_FrontSecondaryColor gl_BackSecondaryColor gl_Color gl_SecondaryColor
|
||||
subroutine gl_Position gl_FragCoord
|
||||
gl_VertexID gl_InstanceID gl_Normal gl_Vertex gl_MultiTexCoord0 gl_MultiTexCoord1
|
||||
@@ -76,22 +76,26 @@ return {
|
||||
gl_InvocationID gl_PrimitiveIDIn gl_Layer gl_ViewportIndex gl_FrontFacing
|
||||
gl_PointCoord gl_SampleID gl_SamplePosition gl_FragColor
|
||||
gl_FragData gl_FragDepth gl_SampleMask
|
||||
gl_NumWorkGroups gl_WorkGroupSize gl_WorkGroupID gl_LocalInvocationID gl_GlobalInvocationID gl_LocalInvocationIndex
|
||||
local_size_x local_size_y local_size_z
|
||||
|
||||
coherent volatile restrict
|
||||
coherent volatile restrict readonly writeonly
|
||||
image1D image2D image3D image2DRect imageCube imageBuffer image1DArray image2DArray imageCubeArray image2DMS image2DMSArray
|
||||
uimage1D uimage2D uimage3D uimage2DRect uimageCube uimageBuffer uimage1DArray uimage2DArray uimageCubeArray uimage2DMS uimage2DMSArray
|
||||
iimage1D iimage2D iimage3D iimage2DRect iimageCube iimageBuffer iimage1DArray iimage2DArray iimageCubeArray iimage2DMS iimage2DMSArray
|
||||
size1x8 size1x16 size1x32 size2x32 size4x32
|
||||
size1x8 size1x16 size1x32 size2x32 size4x32 rgba32f rgba16f rg32f rg16f r32f r16f rgba8 rgba16 r11f_g11f_b10f rgb10_a2ui
|
||||
rgb10_a2i rg16 rg8 r16 r8 rgba32i rgba16i rgba8i rg32i rg16i rg8i r32i r16i r8i rgba32ui rgba16ui rgba8ui rg32ui rg16ui rg8ui
|
||||
r32ui r16ui r8ui rgba16_snorm rgba8_snorm rg16_snorm rg8_snorm r16_snorm r8_snorm
|
||||
]],
|
||||
|
||||
[[discard
|
||||
radians degrees sin cos tan asin acos atan sinh cosh tanh asinh acosh atanh
|
||||
pow exp log exp2 log2 sqrt inversesqrt abs sign floor trunc round
|
||||
roundEven ceil fract mod modf min max mix step isnan isinf clamp smoothstep
|
||||
floatBitsToInt intBitsToFloat uintBitsToFloat fma frexp ldexp
|
||||
floatBitsToInt floatBitsToUint intBitsToFloat uintBitsToFloat fma frexp ldexp
|
||||
packUnorm2x16 packUnorm4x8 packSnorm4x8
|
||||
unpackUnorm2x16 unpackUnorm4x8 unpackSnorm4x8
|
||||
packDouble2x32 unpackDouble2x32
|
||||
packDouble2x32 unpackDouble2x32 packHalf2x16 unpackHalf2x16
|
||||
length distance dot cross normalize ftransform faceforward
|
||||
reflect refract
|
||||
matrixCompMult outerProduct transpose determinant inverse
|
||||
@@ -138,7 +142,12 @@ return {
|
||||
imageAtomicAdd imageAtomicMin imageAtomicMax
|
||||
imageAtomicIncWrap imageAtomicDecWrap imageAtomicAnd
|
||||
imageAtomicOr imageAtomixXor imageAtomicExchange
|
||||
imageCompSwap memoryBarrier
|
||||
imageCompSwap
|
||||
|
||||
memoryBarrier groupMemoryBarrier memoryBarrierAtomicCounter memoryBarrierShared memoryBarrierBuffer memoryBarrierImage
|
||||
|
||||
atomicCounterIncrement atomicCounterDecrement atomicCounter
|
||||
atomicMin atomicMax atomicAdd atomicAnd atomicOr atomicXor atomicExchange atomicCompSwap
|
||||
|
||||
x y z w
|
||||
xxxx xxxy xxxz xxxw xxyx xxyy xxyz xxyw xxzx xxzy
|
||||
|
||||
17
spec/lua.lua
17
spec/lua.lua
@@ -1,30 +1,27 @@
|
||||
-- authors: Luxinia Dev (Eike Decker & Christoph Kubisch)
|
||||
---------------------------------------------------------
|
||||
|
||||
local funcdef = "([A-Za-z_][A-Za-z0-9_%.%:]*)%s*"
|
||||
local funccall = "([A-Za-z_][A-Za-z0-9_]*)%s*"
|
||||
return {
|
||||
exts = {"lua"},
|
||||
exts = {"lua", "rockspec"},
|
||||
lexer = wxstc.wxSTC_LEX_LUA,
|
||||
apitype = "lua",
|
||||
linecomment = "--",
|
||||
sep = "%.:",
|
||||
isfncall = function(str)
|
||||
return string.find(str,"([A-Za-z0-9_]+)%s*%(")
|
||||
return string.find(str, funccall .. "%(")
|
||||
end,
|
||||
isfndef = function(str)
|
||||
local l
|
||||
local s,e,cap,par = string.find(str,"function%s+([A-Za-z0-9_]+%s-[%.%:]?%s-[A-Za-z0-9_]*)%s*(%(.-%))")
|
||||
local s,e,cap,par = string.find(str, "function%s+" .. funcdef .. "(%(.-%))")
|
||||
-- try to match without brackets now, but only at the beginning of the line
|
||||
if (not s) then
|
||||
s,e,cap = string.find(str,"^%s*function%s+([A-Za-z0-9_]+%s-[%.%:]?%s-[A-Za-z0-9_]*)%s*")
|
||||
s,e,cap = string.find(str, "^%s*function%s+" .. funcdef)
|
||||
end
|
||||
-- try to match "foo = function()"
|
||||
if (not s) then
|
||||
s,e,cap,cap1,cap2,par = string.find(str,"(([A-Za-z0-9_]+%s-[%.%:]?%s-)([A-Za-z0-9_]*))%s*=%s*function%s*(%(.-%))")
|
||||
-- check if we captured 'local foo =' instead of 'foo.bar ='
|
||||
if cap1 and cap2 and string.len(cap2) > 0 and not string.find(cap1,'[%.%:]') then
|
||||
cap = cap2
|
||||
s = s + string.len(cap1)
|
||||
end
|
||||
s,e,cap,par = string.find(str, funcdef .. "=%s*function%s*(%(.-%))")
|
||||
end
|
||||
if (s) then
|
||||
l = string.find(string.sub(str,1,s-1),"local%s+$")
|
||||
|
||||
25
src/defs.lua
25
src/defs.lua
@@ -112,6 +112,12 @@ config = {
|
||||
whitespace = false,
|
||||
autotabs = true, -- if true test for tabs after file load,
|
||||
-- sets "usetabs" to true for this file
|
||||
calltipdelay = nil, -- delay to show calltip (in ms)
|
||||
},
|
||||
|
||||
default = {
|
||||
name = 'untitled',
|
||||
fullname = 'untitled.lua',
|
||||
},
|
||||
|
||||
debugger = {
|
||||
@@ -168,7 +174,7 @@ config = {
|
||||
-- UDP port for single instance communication
|
||||
|
||||
activateoutput = false, -- activate output/console on Run/Debug/Compile
|
||||
unhidewxwindow = false, -- try to unhide a wx window
|
||||
unhidewindow = false, -- to unhide a gui window
|
||||
allowinteractivescript = false, -- allow interaction in the output window
|
||||
}
|
||||
|
||||
@@ -301,21 +307,18 @@ debuginterface = {
|
||||
breakpoint = function(self,file,line,state) end, -- set breakpoint state
|
||||
|
||||
-- returns result table if successful
|
||||
evaluate = function(self, expressions, fnSetValues) end, -- for watches tables expected
|
||||
|
||||
-- NYI getstack = function(self, fnSetValues ) end, -- get stack information
|
||||
evaluate = function(self, expressions, fnSetValues) end, -- for watches tables
|
||||
stack = function(self) end, -- get stack information
|
||||
}
|
||||
|
||||
-- interpreter definition-- ----------------------------------------------------
|
||||
interpreter = {
|
||||
name = "",
|
||||
description = "",
|
||||
api = {"apifile_without_extension"} -- optional to limit loaded lua apis
|
||||
frun = function(self,wfilename,withdebugger)
|
||||
end,
|
||||
fprojdir = function(self,wfilename)
|
||||
return "projpath_from_filename" -- optional
|
||||
end,
|
||||
fattachdebug = function(self) end, -- optional
|
||||
api = {"apifile_without_extension"} -- (opt) to limit loaded lua apis
|
||||
frun = function(self,wfilename,withdebugger) end,
|
||||
fprojdir = function(self,wfilename) return "projpath_from_filename" end, -- (opt)
|
||||
fattachdebug = function(self) end, -- (opt)
|
||||
hasdebugger = false, -- if debugging is available
|
||||
scratchextloop = false, -- (opt) if scratchpad requires handling for external loop
|
||||
}
|
||||
|
||||
@@ -89,8 +89,8 @@ local function addAPI(apifile,only,subapis,known) -- relative to API directory
|
||||
end
|
||||
|
||||
local function loadallAPIs (only,subapis,known)
|
||||
for i,dir in ipairs(FileSysGet(".\\api\\*.*",wx.wxDIR)) do
|
||||
local files = FileSysGet(dir.."\\*.*",wx.wxFILE)
|
||||
for i,dir in ipairs(FileSysGet("./api/*",wx.wxDIR)) do
|
||||
local files = FileSysGet(dir.."/*.*",wx.wxFILE)
|
||||
for i,file in ipairs(files) do
|
||||
if file:match "%.lua$" then
|
||||
addAPI(file,only,subapis,known)
|
||||
|
||||
@@ -8,7 +8,7 @@ local openDocuments = ide.openDocuments
|
||||
local uimgr = frame.uimgr
|
||||
|
||||
function NewFile(event)
|
||||
local editor = CreateEditor("untitled.lua")
|
||||
local editor = CreateEditor(ide.config.default.fullname)
|
||||
SetupKeywords(editor, "lua")
|
||||
end
|
||||
|
||||
@@ -27,29 +27,24 @@ local function findDocumentToReuse()
|
||||
end
|
||||
|
||||
function LoadFile(filePath, editor, file_must_exist)
|
||||
filePath = wx.wxFileName(filePath):GetFullPath()
|
||||
local cmpName = string.lower(string.gsub(filePath, "\\", "/"))
|
||||
|
||||
-- prevent files from being reopened again
|
||||
if (not editor) then
|
||||
local filePath = wx.wxFileName(filePath)
|
||||
for id, doc in pairs(openDocuments) do
|
||||
local docName = doc.filePath and string.lower(string.gsub(doc.filePath, "\\", "/"))
|
||||
if cmpName == docName then
|
||||
if doc.filePath and filePath:SameAs(wx.wxFileName(doc.filePath)) then
|
||||
notebook:SetSelection(doc.index)
|
||||
return doc.editor
|
||||
end
|
||||
end
|
||||
end
|
||||
filePath = wx.wxFileName(filePath):GetFullPath()
|
||||
|
||||
-- if not opened yet, try open now
|
||||
local file_text = ""
|
||||
local handle = io.open(filePath, "rb")
|
||||
if handle then
|
||||
file_text = handle:read("*a")
|
||||
local file_text = FileRead(filePath)
|
||||
if file_text then
|
||||
if GetConfigIOFilter("input") then
|
||||
file_text = GetConfigIOFilter("input")(filePath,file_text)
|
||||
end
|
||||
handle:close()
|
||||
elseif file_must_exist then
|
||||
return nil
|
||||
end
|
||||
@@ -57,7 +52,8 @@ function LoadFile(filePath, editor, file_must_exist)
|
||||
local current = editor and editor:GetCurrentPos()
|
||||
editor = editor
|
||||
or findDocumentToReuse()
|
||||
or CreateEditor(wx.wxFileName(filePath):GetFullName() or "untitled.lua")
|
||||
or CreateEditor(wx.wxFileName(filePath):GetFullName()
|
||||
or ide.config.default.fullname)
|
||||
|
||||
editor:Clear()
|
||||
editor:ClearAll()
|
||||
@@ -82,7 +78,7 @@ function LoadFile(filePath, editor, file_must_exist)
|
||||
IndicateFunctions(editor)
|
||||
|
||||
SettingsAppendFileToHistory(filePath)
|
||||
|
||||
|
||||
-- activate the editor; this is needed for those cases when the editor is
|
||||
-- created from some other element, for example, from a project tree.
|
||||
SetEditorSelection()
|
||||
@@ -115,7 +111,7 @@ function OpenFile(event)
|
||||
"",
|
||||
"",
|
||||
exts,
|
||||
wx.wxOPEN + wx.wxFILE_MUST_EXIST)
|
||||
wx.wxFD_OPEN + wx.wxFD_FILE_MUST_EXIST)
|
||||
if fileDialog:ShowModal() == wx.wxID_OK then
|
||||
if not LoadFile(fileDialog:GetPath(), nil, true) then
|
||||
wx.wxMessageBox("Unable to load file '"..fileDialog:GetPath().."'.",
|
||||
@@ -131,22 +127,15 @@ function SaveFile(editor, filePath)
|
||||
if not filePath then
|
||||
return SaveFileAs(editor)
|
||||
else
|
||||
if (ide.config.savebak) then
|
||||
local backPath = filePath..".bak"
|
||||
os.remove(backPath)
|
||||
os.rename(filePath, backPath)
|
||||
if (ide.config.savebak) then FileRename(filePath, filePath..".bak") end
|
||||
|
||||
local st = editor:GetText()
|
||||
if GetConfigIOFilter("output") then
|
||||
st = GetConfigIOFilter("output")(filePath,st)
|
||||
end
|
||||
|
||||
local handle = io.open(filePath, "wb")
|
||||
if handle then
|
||||
local st = editor:GetText()
|
||||
|
||||
if GetConfigIOFilter("output") then
|
||||
st = GetConfigIOFilter("output")(filePath,st)
|
||||
end
|
||||
handle:write(st)
|
||||
handle:close()
|
||||
--editor:EmptyUndoBuffer()
|
||||
local ok, err = FileWrite(filePath, st)
|
||||
if ok then
|
||||
editor:SetSavePoint()
|
||||
local id = editor:GetId()
|
||||
openDocuments[id].filePath = filePath
|
||||
@@ -155,9 +144,9 @@ function SaveFile(editor, filePath)
|
||||
SetDocumentModified(id, false)
|
||||
return true
|
||||
else
|
||||
wx.wxMessageBox("Unable to save file '"..filePath.."'.",
|
||||
wx.wxMessageBox("Unable to save file '"..filePath.."': "..err,
|
||||
"Error",
|
||||
wx.wxOK + wx.wxCENTRE, ide.frame)
|
||||
wx.wxICON_ERROR + wx.wxOK + wx.wxCENTRE, ide.frame)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -170,7 +159,7 @@ function SaveFileAs(editor)
|
||||
local filePath = openDocuments[id].filePath
|
||||
if (not filePath) then
|
||||
filePath = FileTreeGetDir()
|
||||
filePath = (filePath or "").."untitled"
|
||||
filePath = (filePath or "")..ide.config.default.name
|
||||
end
|
||||
|
||||
local fn = wx.wxFileName(filePath)
|
||||
@@ -182,12 +171,15 @@ function SaveFileAs(editor)
|
||||
fn:GetPath(wx.wxPATH_GET_VOLUME),
|
||||
fn:GetFullName(),
|
||||
exts,
|
||||
wx.wxSAVE)
|
||||
wx.wxFD_SAVE)
|
||||
|
||||
if fileDialog:ShowModal() == wx.wxID_OK then
|
||||
local filePath = fileDialog:GetPath()
|
||||
|
||||
if SaveFile(editor, filePath) then
|
||||
SetEditorSelection() -- update title of the editor
|
||||
FileTreeRefresh() -- refresh the tree to reflect the new file
|
||||
FileTreeMarkSelected(filePath)
|
||||
SetupKeywords(editor, GetFileExt(filePath))
|
||||
IndicateFunctions(editor)
|
||||
if MarkupStyle then MarkupStyle(editor) end
|
||||
@@ -288,7 +280,8 @@ function SaveModifiedDialog(editor, allow_cancel)
|
||||
local filePath = document.filePath
|
||||
local fileName = document.fileName
|
||||
if document.isModified then
|
||||
local message = "Do you want to save the changes to '"..(fileName or 'untitled').."'?"
|
||||
local message = "Do you want to save the changes to '"
|
||||
..(fileName or ide.config.default.name).."'?"
|
||||
local dlg_styles = wx.wxYES_NO + wx.wxCENTRE + wx.wxICON_QUESTION
|
||||
if allow_cancel then dlg_styles = dlg_styles + wx.wxCANCEL end
|
||||
local dialog = wx.wxMessageDialog(ide.frame, message,
|
||||
@@ -311,8 +304,13 @@ function SaveOnExit(allow_cancel)
|
||||
if (SaveModifiedDialog(document.editor, allow_cancel) == wx.wxID_CANCEL) then
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
document.isModified = false
|
||||
-- if all documents have been saved or refused to save, then mark those that
|
||||
-- are still modified as not modified (they don't need to be saved)
|
||||
-- to keep their tab names correct
|
||||
for id, document in pairs(openDocuments) do
|
||||
if document.isModified then SetDocumentModified(id, false) end
|
||||
end
|
||||
|
||||
return true
|
||||
@@ -398,7 +396,10 @@ function ClearAllCurrentLineMarkers()
|
||||
end
|
||||
|
||||
function CompileProgram(editor, quiet)
|
||||
local editorText = editor:GetText()
|
||||
-- remove shebang line (#!) as it throws a compilation error as
|
||||
-- loadstring() doesn't allow it even though lua/loadfile accepts it.
|
||||
-- replace with a new line to keep the number of lines the same.
|
||||
local editorText = editor:GetText():gsub("^#!.-\n", "\n")
|
||||
local id = editor:GetId()
|
||||
local filePath = DebuggerMakeFileName(editor, openDocuments[id].filePath)
|
||||
local _, errMsg, line_num = wxlua.CompileLuaScript(editorText, filePath)
|
||||
@@ -496,7 +497,8 @@ function ShowFullScreen(setFullScreen)
|
||||
|
||||
uimgr:GetPane("toolBar"):Show(not setFullScreen)
|
||||
uimgr:Update()
|
||||
frame:ShowFullScreen(setFullScreen)
|
||||
-- protect from systems that don't have ShowFullScreen (GTK on linux?)
|
||||
pcall(function() frame:ShowFullScreen(setFullScreen) end)
|
||||
end
|
||||
|
||||
function CloseWindow(event)
|
||||
@@ -514,10 +516,14 @@ function CloseWindow(event)
|
||||
SettingsSaveView()
|
||||
SettingsSaveFramePosition(ide.frame, "MainFrame")
|
||||
SettingsSaveEditorSettings()
|
||||
DebuggerCloseWatchWindow()
|
||||
DebuggerCloseStackWindow()
|
||||
DebuggerShutdown()
|
||||
if DebuggerCloseWatchWindow then DebuggerCloseWatchWindow() end
|
||||
if DebuggerCloseStackWindow then DebuggerCloseStackWindow() end
|
||||
if DebuggerShutdown then DebuggerShutdown() end
|
||||
ide.settings:delete() -- always delete the config
|
||||
event:Skip()
|
||||
|
||||
-- without explicit exit() the IDE crashes with SIGILL exception when closed
|
||||
-- on MacOS compiled under 64bit with wxwidgets 2.9.3
|
||||
if ide.osname == "Macintosh" then os.exit() end
|
||||
end
|
||||
frame:Connect(wx.wxEVT_CLOSE_WINDOW, CloseWindow)
|
||||
|
||||
@@ -139,21 +139,15 @@ end
|
||||
local function activateDocument(fileName, line)
|
||||
if not fileName then return end
|
||||
|
||||
if not wx.wxIsAbsolutePath(fileName) then
|
||||
fileName = wx.wxGetCwd().."/"..fileName
|
||||
end
|
||||
|
||||
if wx.__WXMSW__ then
|
||||
fileName = wx.wxUnix2DosFilename(fileName)
|
||||
if not wx.wxIsAbsolutePath(fileName) and debugger.basedir then
|
||||
fileName = debugger.basedir .. fileName
|
||||
end
|
||||
|
||||
local activated
|
||||
local fileName = wx.wxFileName(fileName)
|
||||
for _, document in pairs(ide.openDocuments) do
|
||||
local editor = document.editor
|
||||
-- for running in cygwin, use same type of separators
|
||||
local filePath = string.gsub(document.filePath, "\\", "/")
|
||||
local fileName = string.gsub(fileName, "\\", "/")
|
||||
if string.upper(filePath) == string.upper(fileName) then
|
||||
if fileName:SameAs(wx.wxFileName(document.filePath)) then
|
||||
local editor = document.editor
|
||||
local selection = document.index
|
||||
notebook:SetSelection(selection)
|
||||
SetEditorSelection(selection)
|
||||
@@ -196,8 +190,8 @@ debugger.shell = function(expression, isstatement)
|
||||
-- exec command is not expected to return anything.
|
||||
-- eval command returns 0 or more results.
|
||||
-- 'values' has a list of serialized results returned.
|
||||
-- as it is not possible to distinguish between 0 and nil returned,
|
||||
-- 'nil' is always returned in this case.
|
||||
-- as it is not possible to distinguish between 0 results and one
|
||||
-- 'nil' value returned, 'nil' is always returned in this case.
|
||||
-- the first value returned by eval command is not used;
|
||||
-- this may need to be taken into account by other debuggers.
|
||||
local addedret, forceexpression = true, expression:match("^%s*=%s*")
|
||||
@@ -205,6 +199,7 @@ debugger.shell = function(expression, isstatement)
|
||||
local _, values, err = debugger.evaluate(expression)
|
||||
if not forceexpression and err and
|
||||
(err:find("'<eof>' expected near '") or
|
||||
err:find("'%(' expected near") or
|
||||
err:find("unexpected symbol near '")) then
|
||||
_, values, err = debugger.execute(expression)
|
||||
addedret = false
|
||||
@@ -214,12 +209,29 @@ debugger.shell = function(expression, isstatement)
|
||||
if addedret then err = err:gsub('^%[string "return ', '[string "') end
|
||||
DisplayShellErr(err)
|
||||
elseif addedret or #values > 0 then
|
||||
if forceexpression then -- display elements as multi-line
|
||||
local mobdebug = require "mobdebug"
|
||||
for i,v in pairs(values) do -- stringify each of the returned values
|
||||
local func = loadstring('return '..v) -- deserialize the value first
|
||||
if func then -- if it's deserialized correctly
|
||||
values[i] = (forceexpression and i > 1 and '\n' or '') ..
|
||||
mobdebug.line(func(), {nocode = true, comment = 0,
|
||||
-- if '=' is used, then use multi-line serialized output
|
||||
indent = forceexpression and ' ' or nil})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- if empty table is returned, then show nil if this was an expression
|
||||
if #values == 0 and (forceexpression or not isstatement) then
|
||||
values = {'nil'}
|
||||
end
|
||||
DisplayShell((table.unpack or unpack)(values))
|
||||
end
|
||||
|
||||
-- refresh Stack and Watch windows if executed a statement (and no err)
|
||||
if isstatement and not err and not addret and #values == 0 then
|
||||
updateStackSync() updateWatchesSync() end
|
||||
end)
|
||||
end
|
||||
end
|
||||
@@ -235,6 +247,11 @@ debugger.listen = function()
|
||||
return
|
||||
end
|
||||
|
||||
copas.setErrorHandler(function(error)
|
||||
DisplayOutput("Can't start debugging session due to internal error '" .. error .. "'.\n")
|
||||
debugger.terminate()
|
||||
end)
|
||||
|
||||
local options = debugger.options or {}
|
||||
if not debugger.scratchpad then SetAllEditorsReadOnly(true) end
|
||||
local wxfilepath = GetEditorFileAndCurInfo()
|
||||
@@ -248,6 +265,7 @@ debugger.listen = function()
|
||||
debugger.socket = skt
|
||||
debugger.loop = false
|
||||
debugger.scratchable = false
|
||||
debugger.stats = {line = 0}
|
||||
|
||||
-- load the remote file into the debugger
|
||||
-- set basedir first, before loading to make sure that the path is correct
|
||||
@@ -255,9 +273,15 @@ debugger.listen = function()
|
||||
|
||||
reSetBreakpoints()
|
||||
|
||||
if (options.run) then
|
||||
local file, line = debugger.handle("run")
|
||||
activateDocument(file, line)
|
||||
if (options.startwith) then
|
||||
local file, line, err = debugger.loadfile(options.startwith)
|
||||
if err then
|
||||
DisplayOutput(("Can't run the entry point script (%s). Compilation error:\n%s\n")
|
||||
:format(options.startwith, err))
|
||||
return debugger.terminate()
|
||||
end
|
||||
elseif (options.run) then
|
||||
-- do nothing here
|
||||
elseif (debugger.scratchpad) then
|
||||
debugger.scratchpad.updated = true
|
||||
else
|
||||
@@ -267,27 +291,17 @@ debugger.listen = function()
|
||||
-- with start() method, which can't load new files
|
||||
-- if file and line are set, this indicates option #2
|
||||
if file and line then
|
||||
-- if the file name is absolute, try to load it
|
||||
local activated
|
||||
if wx.wxIsAbsolutePath(file) then
|
||||
activated = activateDocument(file, line)
|
||||
else
|
||||
-- try to find a proper file based on file name
|
||||
-- first check using basedir that was set based on current file path
|
||||
if not activated then
|
||||
activated = activateDocument(debugger.basedir..file, line)
|
||||
end
|
||||
local activated = activateDocument(file, line)
|
||||
|
||||
-- if not found, check using full file path and reset basedir
|
||||
if not activated then
|
||||
local path = wxfilepath:GetPath(wx.wxPATH_GET_VOLUME + wx.wxPATH_GET_SEPARATOR)
|
||||
activated = activateDocument(path..file, line)
|
||||
if activated then
|
||||
debugger.basedir = path
|
||||
debugger.handle("basedir " .. debugger.basedir)
|
||||
-- reset breakpoints again as basedir has changed
|
||||
reSetBreakpoints()
|
||||
end
|
||||
-- if not found, check using full file path and reset basedir
|
||||
if not activated then
|
||||
local path = wxfilepath:GetPath(wx.wxPATH_GET_VOLUME + wx.wxPATH_GET_SEPARATOR)
|
||||
activated = activateDocument(path..file, line)
|
||||
if activated then
|
||||
debugger.basedir = path
|
||||
debugger.handle("basedir " .. debugger.basedir)
|
||||
-- reset breakpoints again as basedir has changed
|
||||
reSetBreakpoints()
|
||||
end
|
||||
end
|
||||
|
||||
@@ -315,6 +329,16 @@ debugger.listen = function()
|
||||
|
||||
DisplayOutput(("Debugging session started in '%s'.\n")
|
||||
:format(debugger.basedir))
|
||||
|
||||
if (options.runstart) then
|
||||
ClearAllCurrentLineMarkers()
|
||||
debugger.run()
|
||||
end
|
||||
|
||||
if (options.run) then
|
||||
local file, line = debugger.handle("run")
|
||||
activateDocument(file, line)
|
||||
end
|
||||
end)
|
||||
debugger.listening = true
|
||||
end
|
||||
@@ -349,10 +373,8 @@ debugger.exec = function(command)
|
||||
DebuggerStop()
|
||||
return
|
||||
else
|
||||
if debugger.basedir and not wx.wxIsAbsolutePath(file) then
|
||||
file = debugger.basedir .. file
|
||||
end
|
||||
if activateDocument(file, line) then
|
||||
debugger.stats.line = debugger.stats.line + 1
|
||||
if debugger.loop then
|
||||
updateStackSync()
|
||||
updateWatchesSync()
|
||||
@@ -361,7 +383,15 @@ debugger.exec = function(command)
|
||||
return
|
||||
end
|
||||
else
|
||||
out = "out" -- redo now trying to get out of this file
|
||||
-- redo now; if the call is from the debugger, then repeat
|
||||
-- the same command, except when it was "run" (switch to 'step');
|
||||
-- this is needed to "break" execution that happens in on() call.
|
||||
-- in all other cases get out of this file.
|
||||
-- don't get out of "mobdebug", because it may happen with
|
||||
-- start() or on() call, which will get us out of the current
|
||||
-- file, which is not what we want.
|
||||
out = (file:find('mobdebug%.lua$')
|
||||
and (command == 'run' and 'step' or command) or "out")
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -427,6 +457,17 @@ end
|
||||
debugger.breakpoint = function(file, line, state)
|
||||
debugger.handleAsync((state and "setb " or "delb ") .. file .. " " .. line)
|
||||
end
|
||||
debugger.quickeval = function(var, callback)
|
||||
if debugger.server and not debugger.running then
|
||||
copas.addthread(function ()
|
||||
local _, values, err = debugger.evaluate(var)
|
||||
local val = err
|
||||
and err:gsub("%[.-%]:%d+:%s*","error: ")
|
||||
or (var .. " = " .. (#values > 0 and values[1] or 'nil'))
|
||||
if callback then callback(val) end
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
----------------------------------------------
|
||||
-- public api
|
||||
@@ -450,7 +491,13 @@ function DebuggerStop()
|
||||
ShellSupportRemote(nil)
|
||||
ClearAllCurrentLineMarkers()
|
||||
DebuggerScratchpadOff()
|
||||
DisplayOutput("Debugging session completed.\n")
|
||||
DisplayOutput(("Debugging session completed (traced %d instruction%s).\n")
|
||||
:format(debugger.stats.line, debugger.stats.line == 1 and '' or 's'))
|
||||
else
|
||||
-- it's possible that the application couldn't start, or that the
|
||||
-- debugger in the application didn't start, which means there is
|
||||
-- no debugger.server, but scratchpad may still be on. Turn it off.
|
||||
DebuggerScratchpadOff()
|
||||
end
|
||||
end
|
||||
|
||||
@@ -474,17 +521,18 @@ end
|
||||
-- of it and if done inside a function, icons do not work as expected
|
||||
local imglist = wx.wxImageList(16,16)
|
||||
do
|
||||
local getBitmap = (ide.app.createbitmap or wx.wxArtProvider.GetBitmap)
|
||||
local size = wx.wxSize(16,16)
|
||||
-- 0 = stack call
|
||||
imglist:Add((ide.app.createbitmap or wx.wxArtProvider.GetBitmap)(wx.wxART_GO_FORWARD, wx.wxART_OTHER, size))
|
||||
imglist:Add(getBitmap(wx.wxART_GO_FORWARD, wx.wxART_OTHER, size))
|
||||
-- 1 = local variables
|
||||
imglist:Add((ide.app.createbitmap or wx.wxArtProvider.GetBitmap)(wx.wxART_LIST_VIEW, wx.wxART_OTHER, size))
|
||||
imglist:Add(getBitmap(wx.wxART_LIST_VIEW, wx.wxART_OTHER, size))
|
||||
-- 2 = upvalues
|
||||
imglist:Add((ide.app.createbitmap or wx.wxArtProvider.GetBitmap)(wx.wxART_REPORT_VIEW, wx.wxART_OTHER, size))
|
||||
imglist:Add(getBitmap(wx.wxART_REPORT_VIEW, wx.wxART_OTHER, size))
|
||||
end
|
||||
|
||||
function DebuggerCreateStackWindow()
|
||||
if (debugger.stackWindow) then return end
|
||||
if (debugger.stackWindow) then return updateStackAndWatches() end
|
||||
local width = 360
|
||||
local stackWindow = wx.wxFrame(ide.frame, wx.wxID_ANY,
|
||||
"Stack Window",
|
||||
@@ -542,7 +590,7 @@ function DebuggerCreateStackWindow()
|
||||
end
|
||||
|
||||
function DebuggerCreateWatchWindow()
|
||||
if (debugger.watchWindow) then return end
|
||||
if (debugger.watchWindow) then return updateWatches() end
|
||||
local width = 360
|
||||
local watchWindow = wx.wxFrame(ide.frame, wx.wxID_ANY,
|
||||
"Watch Window",
|
||||
@@ -651,10 +699,7 @@ function DebuggerCreateWatchWindow()
|
||||
end
|
||||
|
||||
function DebuggerMakeFileName(editor, filePath)
|
||||
if not filePath then
|
||||
filePath = "file"..tostring(editor)
|
||||
end
|
||||
return filePath
|
||||
return filePath or ide.config.default.fullname
|
||||
end
|
||||
|
||||
function DebuggerToggleBreakpoint(editor, line)
|
||||
@@ -684,7 +729,7 @@ function DebuggerRefreshScratchpad()
|
||||
if debugger.scratchpad.running then
|
||||
-- break the current execution first
|
||||
-- don't try too frequently to avoid overwhelming the debugger
|
||||
local now = os.clock()
|
||||
local now = TimeGet()
|
||||
if now - debugger.scratchpad.running > 0.250 then
|
||||
debugger.breaknow()
|
||||
debugger.scratchpad.running = now
|
||||
@@ -692,21 +737,37 @@ function DebuggerRefreshScratchpad()
|
||||
else
|
||||
local clear = ide.frame.menuBar:IsChecked(ID_CLEAROUTPUT)
|
||||
local scratchpadEditor = debugger.scratchpad.editor
|
||||
local code = scratchpadEditor:GetText()
|
||||
-- take editor text and remove shebang line
|
||||
local code = scratchpadEditor:GetText():gsub("^#!.-\n", "\n")
|
||||
local filePath = DebuggerMakeFileName(scratchpadEditor,
|
||||
ide.openDocuments[scratchpadEditor:GetId()].filePath)
|
||||
|
||||
-- this is a special error message that is generated at the very end
|
||||
-- of each script to avoid exiting the (debugee) scratchpad process.
|
||||
-- these errors are handled and not reported to the user
|
||||
local errormsg = 'execution suspended at ' .. os.clock()
|
||||
local errormsg = 'execution suspended at ' .. TimeGet()
|
||||
local stopper = "\ndo error('" .. errormsg .. "') end"
|
||||
-- store if interpreter requires a special handling for external loop
|
||||
local extloop = ide.interpreter.scratchextloop
|
||||
|
||||
local function reloadScratchpadCode()
|
||||
debugger.scratchpad.running = os.clock()
|
||||
debugger.scratchpad.running = TimeGet()
|
||||
debugger.scratchpad.updated = false
|
||||
debugger.scratchpad.runs = (debugger.scratchpad.runs or 0) + 1
|
||||
|
||||
-- the code can be running in two ways under scratchpad:
|
||||
-- 1. controlled by the application, requires stopper (most apps)
|
||||
-- 2. controlled by some external loop (for example, love2d).
|
||||
-- in the first case we need to reload the app after each change
|
||||
-- in the second case, we need to load the app once and then
|
||||
-- "execute" new code to reflect the changes (with some limitations).
|
||||
local _, _, err
|
||||
if extloop then -- if the execution is controlled by an external loop
|
||||
if debugger.scratchpad.runs == 1
|
||||
then _, _, err = debugger.loadstring(filePath, code)
|
||||
else _, _, err = debugger.execute(code) end
|
||||
else _, _, err = debugger.loadstring(filePath, code .. stopper) end
|
||||
|
||||
local _, _, err = debugger.loadstring(filePath, code .. stopper)
|
||||
local prefix = "Compilation error"
|
||||
|
||||
if clear then ClearOutput() end
|
||||
|
||||
@@ -18,7 +18,7 @@ local projcombobox = ide.frame.projpanel.projcombobox
|
||||
local statusTextTable = { "OVR?", "R/O?", "Cursor Pos" }
|
||||
|
||||
-- set funclist font to be the same as the combobox in the project dropdown
|
||||
funclist:SetFont(projcombobox:GetFont())
|
||||
funclist:SetFont(ide.font.fNormal)
|
||||
|
||||
local function updateStatusText(editor)
|
||||
local texts = { "", "", "" }
|
||||
@@ -27,9 +27,10 @@ local function updateStatusText(editor)
|
||||
local line = editor:LineFromPosition(pos)
|
||||
local col = 1 + pos - editor:PositionFromLine(line)
|
||||
|
||||
texts = { iff(editor:GetOvertype(), "OVR", "INS"),
|
||||
texts = {
|
||||
iff(editor:GetOvertype(), "OVR", "INS"),
|
||||
iff(editor:GetReadOnly(), "R/O", "R/W"),
|
||||
"Ln "..tostring(line + 1).." Col "..tostring(col) }
|
||||
"Ln: "..tostring(line + 1).." Col: "..tostring(col) }
|
||||
end
|
||||
|
||||
if ide.frame then
|
||||
@@ -139,8 +140,6 @@ function SetEditorSelection(selection)
|
||||
statusBar:SetStatusText("",1)
|
||||
ide.frame:SetTitle(getFileTitle(editor))
|
||||
|
||||
FileTreeMarkSelected('')
|
||||
|
||||
if editor then
|
||||
if funclist:IsEmpty() then funclist:Append('Jump to a function definition...', 0) end
|
||||
funclist:SetSelection(0)
|
||||
@@ -151,6 +150,8 @@ function SetEditorSelection(selection)
|
||||
if openDocuments[id] and openDocuments[id].filePath then
|
||||
FileTreeMarkSelected(openDocuments[id].filePath)
|
||||
end
|
||||
else
|
||||
FileTreeMarkSelected('')
|
||||
end
|
||||
end
|
||||
|
||||
@@ -181,7 +182,7 @@ end
|
||||
|
||||
-- Set if the document is modified and update the notebook page text
|
||||
function SetDocumentModified(id, modified)
|
||||
local pageText = openDocuments[id].fileName or "untitled.lua"
|
||||
local pageText = openDocuments[id].fileName or ide.config.default.fullname
|
||||
|
||||
if modified then
|
||||
pageText = "* "..pageText
|
||||
@@ -191,6 +192,83 @@ function SetDocumentModified(id, modified)
|
||||
notebook:SetPageText(openDocuments[id].index, pageText)
|
||||
end
|
||||
|
||||
function EditorAutoComplete(editor)
|
||||
if (editor == nil or not editor.spec) then return end
|
||||
|
||||
-- retrieve the current line and get a string to the current cursor position in the line
|
||||
local pos = editor:GetCurrentPos()
|
||||
local line = editor:GetCurrentLine()
|
||||
local linetx = editor:GetLine(line)
|
||||
local linestart = editor:PositionFromLine(line)
|
||||
local localpos = pos-linestart
|
||||
|
||||
local lt = linetx:sub(1,localpos)
|
||||
lt = lt:gsub("%s*("..editor.spec.sep..")%s*",function(a) return a end)
|
||||
lt = lt:gsub("%s*%b[]%s*","")
|
||||
lt = lt:gsub("%s*%b()%s*","")
|
||||
lt = lt:gsub("%s*%b{}%s*","")
|
||||
lt = lt:match("[^%[%(%s]*$")
|
||||
lt = lt:gsub("%s","")
|
||||
|
||||
-- know now which string is to be completed
|
||||
local userList = CreateAutoCompList(editor,lt)
|
||||
if userList and string.len(userList) > 0 then
|
||||
editor:UserListShow(1, userList)
|
||||
elseif editor:AutoCompActive() then
|
||||
editor:AutoCompCancel()
|
||||
end
|
||||
end
|
||||
|
||||
function EditorCallTip(editor, pos)
|
||||
local line = editor:LineFromPosition(pos)
|
||||
local linetx = editor:GetLine(line)
|
||||
local linestart = editor:PositionFromLine(line)
|
||||
local localpos = pos-linestart
|
||||
|
||||
local ident = "([a-zA-Z_0-9][a-zA-Z_0-9%.%:]*)"
|
||||
local linetxtopos = linetx:sub(1,localpos)
|
||||
linetxtopos = linetxtopos..")"
|
||||
linetxtopos = linetxtopos:match(ident .. "%b()$")
|
||||
|
||||
local tip = linetxtopos and GetTipInfo(editor,linetxtopos.."(",false)
|
||||
if ide.debugger and ide.debugger.server then
|
||||
local selected = editor:GetSelectionStart() ~= editor:GetSelectionEnd()
|
||||
and pos >= editor:GetSelectionStart() and pos <= editor:GetSelectionEnd()
|
||||
|
||||
-- check if we have a selected text or an identifier
|
||||
-- for an identifier, check fragments on the left and on the right.
|
||||
-- this is to match 'io' in 'i^o.print' and 'io.print' in 'io.pr^int'.
|
||||
-- remove square brackets to make tbl[index].x show proper values.
|
||||
local start = linetx:sub(1,localpos)
|
||||
:gsub("%b[]", function(s) return ("."):rep(#s) end)
|
||||
:find(ident.."$")
|
||||
|
||||
-- check if the style is the right one; this is to ignore
|
||||
-- comments, strings, numbers (to avoid '1 = 1'), keywords, and such
|
||||
if start and not selected then
|
||||
local style = bit.band(editor:GetStyleAt(linestart+start),31)
|
||||
if editor.spec.iscomment[style]
|
||||
or editor.spec.isstring[style]
|
||||
or style == wxstc.wxSTC_LUA_NUMBER
|
||||
or style == wxstc.wxSTC_LUA_WORD then
|
||||
return -- don't do anything for strings or comments or numbers
|
||||
end
|
||||
end
|
||||
|
||||
local right = linetx:sub(localpos+1,#linetx):match("^[a-zA-Z_0-9]*")
|
||||
local var = selected and editor:GetSelectedText()
|
||||
or (start and linetx:sub(start,localpos):gsub(":",".")..right or nil)
|
||||
if var then
|
||||
local limit = 128
|
||||
ide.debugger.quickeval(var, function(val)
|
||||
if #val > limit then val = val:sub(1, limit-3).."..." end
|
||||
editor:CallTipShow(pos, val) end)
|
||||
end
|
||||
elseif tip then
|
||||
editor:CallTipShow(pos, tip)
|
||||
end
|
||||
end
|
||||
|
||||
-- ----------------------------------------------------------------------------
|
||||
-- Create an editor and add it to the notebook
|
||||
function CreateEditor(name)
|
||||
@@ -206,8 +284,8 @@ function CreateEditor(name)
|
||||
editor:SetBufferedDraw(true)
|
||||
editor:StyleClearAll()
|
||||
|
||||
editor:SetFont(ide.font)
|
||||
editor:StyleSetFont(wxstc.wxSTC_STYLE_DEFAULT, ide.font)
|
||||
editor:SetFont(ide.font.eNormal)
|
||||
editor:StyleSetFont(wxstc.wxSTC_STYLE_DEFAULT, ide.font.eNormal)
|
||||
|
||||
editor:SetTabWidth(ide.config.editor.tabwidth or 4)
|
||||
editor:SetIndent(ide.config.editor.tabwidth or 4)
|
||||
@@ -258,6 +336,10 @@ function CreateEditor(name)
|
||||
editor:MarkerDefine(wxstc.wxSTC_MARKNUM_FOLDERMIDTAIL, wxstc.wxSTC_MARK_TCORNER, wx.wxWHITE, grey)
|
||||
grey:delete()
|
||||
|
||||
if ide.config.editor.calltipdelay and ide.config.editor.calltipdelay > 0 then
|
||||
editor:SetMouseDwellTime(ide.config.editor.calltipdelay)
|
||||
end
|
||||
|
||||
editor:AutoCompSetIgnoreCase(ide.config.acandtip.ignorecase)
|
||||
if (ide.config.acandtip.strategy > 0) then
|
||||
editor:AutoCompSetAutoHide(0)
|
||||
@@ -334,26 +416,37 @@ function CreateEditor(name)
|
||||
editor:GotoPos(pos+indent)
|
||||
end
|
||||
end
|
||||
elseif ch == ("("):byte() then
|
||||
|
||||
elseif ch == ("("):byte() then
|
||||
local tip = GetTipInfo(editor,linetxtopos,ide.config.acandtip.shorttip)
|
||||
if tip then
|
||||
editor:CallTipShow(pos,tip)
|
||||
end
|
||||
|
||||
elseif ide.config.autocomplete then -- code completion prompt
|
||||
|
||||
local trigger = linetxtopos:match("["..editor.spec.sep.."%w_]+$")
|
||||
|
||||
if (trigger and (#trigger > 1 or trigger:match("[%.:]"))) then
|
||||
-- defined in menu_edit.lua
|
||||
local commandEvent = wx.wxCommandEvent(wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
ID_AUTOCOMPLETE)
|
||||
wx.wxPostEvent(ide.frame, commandEvent)
|
||||
ide.frame:AddPendingEvent(wx.wxCommandEvent(
|
||||
wx.wxEVT_COMMAND_MENU_SELECTED, ID_AUTOCOMPLETE))
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
editor:Connect(wxstc.wxEVT_STC_DWELLSTART,
|
||||
function (event)
|
||||
local position = editor:PositionFromPointClose(event:GetX(),event:GetY())
|
||||
if position ~= wxstc.wxSTC_INVALID_POSITION then
|
||||
EditorCallTip(editor, position)
|
||||
end
|
||||
event:Skip()
|
||||
end)
|
||||
|
||||
editor:Connect(wxstc.wxEVT_STC_DWELLEND,
|
||||
function (event)
|
||||
if editor:CallTipActive() then editor:CallTipCancel() end
|
||||
event:Skip()
|
||||
end)
|
||||
|
||||
editor:Connect(wxstc.wxEVT_STC_USERLISTSELECTION,
|
||||
function (event)
|
||||
local pos = editor:GetCurrentPos()
|
||||
@@ -363,17 +456,17 @@ function CreateEditor(name)
|
||||
end)
|
||||
|
||||
editor:Connect(wxstc.wxEVT_STC_SAVEPOINTREACHED,
|
||||
function (event)
|
||||
function ()
|
||||
SetDocumentModified(editor:GetId(), false)
|
||||
end)
|
||||
|
||||
editor:Connect(wxstc.wxEVT_STC_SAVEPOINTLEFT,
|
||||
function (event)
|
||||
function ()
|
||||
SetDocumentModified(editor:GetId(), true)
|
||||
end)
|
||||
|
||||
editor:Connect(wxstc.wxEVT_STC_UPDATEUI,
|
||||
function (event)
|
||||
function ()
|
||||
updateStatusText(editor)
|
||||
updateBraceMatch(editor)
|
||||
for _,iv in ipairs(editor.ev) do
|
||||
@@ -389,7 +482,7 @@ function CreateEditor(name)
|
||||
function (event)
|
||||
if MarkupHotspotClick then
|
||||
local position = editor:PositionFromPointClose(event:GetX(),event:GetY())
|
||||
if position ~= wx.wxSTC_INVALID_POSITION then
|
||||
if position ~= wxstc.wxSTC_INVALID_POSITION then
|
||||
if MarkupHotspotClick(position, editor) then return end
|
||||
end
|
||||
end
|
||||
@@ -423,6 +516,9 @@ function CreateEditor(name)
|
||||
then notebook:SetSelection(first)
|
||||
else notebook:AdvanceSelection(true) end
|
||||
else
|
||||
if ide.osname == 'Macintosh' and event:CmdDown() then
|
||||
return -- ignore a key press if Command key is also pressed
|
||||
end
|
||||
event:Skip()
|
||||
end
|
||||
end)
|
||||
@@ -448,10 +544,10 @@ function GetSpec(ext,forcespec)
|
||||
-- search proper spec
|
||||
-- allow forcespec for "override"
|
||||
if ext and not spec then
|
||||
for i,curspec in pairs(ide.specs) do
|
||||
for _,curspec in pairs(ide.specs) do
|
||||
local exts = curspec.exts
|
||||
if (exts) then
|
||||
for n,curext in ipairs(exts) do
|
||||
for _,curext in ipairs(exts) do
|
||||
if (curext == ext) then
|
||||
spec = curspec
|
||||
break
|
||||
@@ -475,16 +571,11 @@ function IndicateFunctions(editor, lines, linee)
|
||||
|
||||
if (lines < 0) then return end
|
||||
|
||||
local isfunc = editor.spec.isfncall
|
||||
local iscomment = editor.spec.iscomment
|
||||
local iskeyword0 = editor.spec.iskeyword0
|
||||
local isfncall = editor.spec.isfncall
|
||||
local isinvalid = {}
|
||||
for i,v in pairs(iscomment) do
|
||||
isinvalid[i] = v
|
||||
end
|
||||
for i,v in pairs(iskeyword0) do
|
||||
isinvalid[i] = v
|
||||
end
|
||||
for i,v in pairs(editor.spec.iscomment) do isinvalid[i] = v end
|
||||
for i,v in pairs(editor.spec.iskeyword0) do isinvalid[i] = v end
|
||||
for i,v in pairs(editor.spec.isstring) do isinvalid[i] = v end
|
||||
|
||||
local INDICS_MASK = wxstc.wxSTC_INDICS_MASK
|
||||
local INDIC0_MASK = wxstc.wxSTC_INDIC0_MASK
|
||||
@@ -501,13 +592,13 @@ function IndicateFunctions(editor, lines, linee)
|
||||
while from do
|
||||
tx = from==1 and tx or string.sub(tx,from)
|
||||
|
||||
local f,t,w = isfunc(tx)
|
||||
local f,t,w = isfncall(tx)
|
||||
|
||||
if (f) then
|
||||
local p = ls+f+off
|
||||
local s = bit.band(editor:GetStyleAt(p),31)
|
||||
editor:StartStyling(p,INDICS_MASK)
|
||||
editor:SetStyling(t-f,isinvalid[s] and 0 or (INDIC0_MASK + 1))
|
||||
editor:SetStyling(#w,isinvalid[s] and 0 or (INDIC0_MASK + 1))
|
||||
off = off + t
|
||||
end
|
||||
from = t and (t+1)
|
||||
@@ -534,11 +625,11 @@ function SetupKeywords(editor, ext, forcespec, styles, font, fontitalic)
|
||||
-- Get the items in the global "wx" table for autocompletion
|
||||
if not wxkeywords then
|
||||
local keyword_table = {}
|
||||
for index, value in pairs(wx) do
|
||||
for index in pairs(wx) do
|
||||
table.insert(keyword_table, "wx."..index.." ")
|
||||
end
|
||||
|
||||
for index, value in pairs(wxstc) do
|
||||
for index in pairs(wxstc) do
|
||||
table.insert(keyword_table, "wxstc."..index.." ")
|
||||
end
|
||||
|
||||
@@ -560,7 +651,7 @@ function SetupKeywords(editor, ext, forcespec, styles, font, fontitalic)
|
||||
end
|
||||
|
||||
StylesApplyToEditor(styles or ide.config.styles, editor,
|
||||
font or ide.font,fontitalic or ide.fontItalic,lexerstyleconvert)
|
||||
font or ide.font.eNormal,fontitalic or ide.font.eItalic,lexerstyleconvert)
|
||||
end
|
||||
|
||||
----------------------------------------------------
|
||||
@@ -588,9 +679,13 @@ funclist:Connect(wx.wxEVT_SET_FOCUS,
|
||||
local linee = editor:GetLineCount()-1
|
||||
for line=lines,linee do
|
||||
local tx = editor:GetLine(line)
|
||||
local s,e,cap,l = editor.spec.isfndef(tx)
|
||||
local s,_,cap,l = editor.spec.isfndef(tx)
|
||||
if (s) then
|
||||
funclist:Append((l and " " or "")..cap,line)
|
||||
local ls = editor:PositionFromLine(line)
|
||||
local style = bit.band(editor:GetStyleAt(ls+s),31)
|
||||
if not (editor.spec.iscomment[style] or editor.spec.isstring[style]) then
|
||||
funclist:Append((l and " " or "")..cap,line)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -30,14 +30,15 @@ local filetree = ide.filetree
|
||||
-- ------------
|
||||
|
||||
do
|
||||
local getBitmap = (ide.app.createbitmap or wx.wxArtProvider.GetBitmap)
|
||||
local size = wx.wxSize(16, 16)
|
||||
filetree.imglist = wx.wxImageList(16,16)
|
||||
-- 0 = directory
|
||||
filetree.imglist:Add(wx.wxArtProvider.GetBitmap(wx.wxART_FOLDER, wx.wxART_OTHER, size))
|
||||
filetree.imglist:Add(getBitmap(wx.wxART_FOLDER, wx.wxART_OTHER, size))
|
||||
-- 1 = file known spec
|
||||
filetree.imglist:Add(wx.wxArtProvider.GetBitmap(wx.wxART_HELP_PAGE, wx.wxART_OTHER, size))
|
||||
filetree.imglist:Add(getBitmap(wx.wxART_HELP_PAGE, wx.wxART_OTHER, size))
|
||||
-- 2 = file rest
|
||||
filetree.imglist:Add(wx.wxArtProvider.GetBitmap(wx.wxART_NORMAL_FILE, wx.wxART_OTHER, size))
|
||||
filetree.imglist:Add(getBitmap(wx.wxART_NORMAL_FILE, wx.wxART_OTHER, size))
|
||||
end
|
||||
|
||||
local function treeAddDir(tree,parent_id,rootdir)
|
||||
@@ -46,15 +47,14 @@ local function treeAddDir(tree,parent_id,rootdir)
|
||||
while true do
|
||||
if not item:IsOk() then break end
|
||||
items[tree:GetItemText(item) .. tree:GetItemImage(item)] = item
|
||||
item, cookie = tree:GetNextChild(item, cookie)
|
||||
item, cookie = tree:GetNextChild(parent_id, cookie)
|
||||
end
|
||||
|
||||
local curr
|
||||
local search = rootdir..string_Pathsep.."*.*"
|
||||
local dirs = FileSysGet(search,wx.wxDIR)
|
||||
local search = rootdir..string_Pathsep.."*"
|
||||
|
||||
-- append directories
|
||||
for _,dir in ipairs(dirs) do
|
||||
for _,dir in ipairs(FileSysGet(search,wx.wxDIR)) do
|
||||
local name = dir:match("%"..string_Pathsep.."("..stringset_File.."+)$")
|
||||
local icon = 0
|
||||
local item = items[name .. icon]
|
||||
@@ -78,8 +78,7 @@ local function treeAddDir(tree,parent_id,rootdir)
|
||||
end
|
||||
|
||||
-- then append files
|
||||
local files = FileSysGet(search,wx.wxFILE)
|
||||
for _,file in ipairs(files) do
|
||||
for _,file in ipairs(FileSysGet(search,wx.wxFILE)) do
|
||||
local name = file:match("%"..string_Pathsep.."("..stringset_File.."+)$")
|
||||
local known = GetSpec(GetFileExt(name))
|
||||
local icon = known and 1 or 2
|
||||
@@ -122,15 +121,17 @@ local function treeGetItemFullName(tree,treedata,item_id)
|
||||
cur = tree:GetItemText(item_id)
|
||||
if cur and string.len(cur) > 0 then str = cur..string_Pathsep..str end
|
||||
end
|
||||
return ((not filetree.showroot) and filetree.projdata.rootdir or "")..str
|
||||
-- as root may already include path separate, normalize the path
|
||||
local fullPath = wx.wxFileName(
|
||||
filetree.showroot and str or filetree.projdata.rootdir .. str)
|
||||
fullPath:Normalize()
|
||||
return fullPath:GetFullPath()
|
||||
end
|
||||
|
||||
local function treeSetRoot(tree,treedata,rootdir)
|
||||
tree:DeleteAllItems()
|
||||
|
||||
if (not wx.wxDirExists(rootdir)) then
|
||||
treedata.root_id = nil
|
||||
tree:AddRoot("Invalid")
|
||||
return
|
||||
end
|
||||
|
||||
@@ -172,7 +173,6 @@ local function treeSetConnectorsAndIcons(tree,treedata)
|
||||
else -- open file
|
||||
if wx.wxFileName(name):FileExists() then
|
||||
LoadFile(name,nil,true)
|
||||
FileTreeMarkSelected(name)
|
||||
else -- stale filetree information; rescan
|
||||
treeAddDir(tree,tree:GetItemParent(item_id),name)
|
||||
end
|
||||
@@ -199,7 +199,8 @@ local projtree = wx.wxTreeCtrl(projpanel, ID "filetree.projtree",
|
||||
or (wx.wxTR_HAS_BUTTONS + wx.wxTR_SINGLE + wx.wxTR_HIDE_ROOT))
|
||||
|
||||
-- use the same font in the combobox as is used in the filetree
|
||||
projcombobox:SetFont(projtree:GetFont())
|
||||
projtree:SetFont(ide.font.fNormal)
|
||||
projcombobox:SetFont(ide.font.fNormal)
|
||||
|
||||
local projTopSizer = wx.wxBoxSizer( wx.wxHORIZONTAL );
|
||||
projTopSizer:Add(projcombobox, 1, wx.wxALL + wx.wxALIGN_LEFT + wx.wxGROW, 0)
|
||||
@@ -284,7 +285,7 @@ local function findItem(tree, match)
|
||||
local node = projtree:GetRootItem()
|
||||
local label = tree:GetItemText(node)
|
||||
|
||||
local s, e = string.find(match, label)
|
||||
local s, e = string.find(match, label, 1, true)
|
||||
if not s or s ~= 1 then return end
|
||||
|
||||
for token in string.gmatch(string.sub(match,e+1), "[^%"..string_Pathsep.."]+") do
|
||||
@@ -298,7 +299,7 @@ local function findItem(tree, match)
|
||||
node = item
|
||||
break
|
||||
end
|
||||
item, cookie = tree:GetNextChild(item, cookie)
|
||||
item, cookie = tree:GetNextChild(node, cookie)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -306,18 +307,32 @@ local function findItem(tree, match)
|
||||
return node
|
||||
end
|
||||
|
||||
local curr_id
|
||||
local curr_file
|
||||
function FileTreeMarkSelected(file)
|
||||
if not file then return end
|
||||
if not file or not filetree.projdirText or #filetree.projdirText == 0 then return end
|
||||
|
||||
local item_id = findItem(projtree, file)
|
||||
if curr_id ~= item_id then
|
||||
if curr_id and projtree:IsBold(curr_id) then
|
||||
projtree:SetItemBold(curr_id, false)
|
||||
|
||||
-- if the select item is different from the current one
|
||||
-- or the current one is the same, but not bold (which may happen when
|
||||
-- the project is changed to one that includes the current item)
|
||||
if curr_file ~= file
|
||||
or item_id and not projtree:IsBold(item_id) then
|
||||
if curr_file then
|
||||
local curr_id = findItem(projtree, curr_file)
|
||||
if curr_id and projtree:IsBold(curr_id) then
|
||||
projtree:SetItemBold(curr_id, false)
|
||||
end
|
||||
end
|
||||
if item_id then
|
||||
projtree:EnsureVisible(item_id)
|
||||
projtree:SetItemBold(item_id, true)
|
||||
curr_id = item_id
|
||||
end
|
||||
curr_file = file
|
||||
projtree:Refresh() -- to force refresh on Mac (ide.osname == 'Macintosh')
|
||||
end
|
||||
end
|
||||
|
||||
function FileTreeRefresh()
|
||||
treeSetRoot(projtree,filetree.projdata,filetree.projdirText)
|
||||
end
|
||||
|
||||
@@ -112,7 +112,7 @@ function findReplace:FindString(reverse)
|
||||
end
|
||||
if posFind == -1 then
|
||||
findReplace.foundString = false
|
||||
ide.frame:SetStatusText("Find text not found.")
|
||||
ide.frame:SetStatusText("Text not found.")
|
||||
else
|
||||
findReplace.foundString = true
|
||||
local start = editor:GetTargetStart()
|
||||
@@ -209,48 +209,36 @@ local function onFileRegister(pos)
|
||||
findReplace.occurrences = findReplace.occurrences + 1
|
||||
end
|
||||
|
||||
local function storefile(file,content)
|
||||
local handle = io.open(file, "wb")
|
||||
if (handle) then
|
||||
handle:write(content)
|
||||
handle:close()
|
||||
end
|
||||
end
|
||||
|
||||
local function ProcInFiles(startdir,mask,subdirs,replace)
|
||||
if (subdirs) then
|
||||
local dirs = FileSysGet(startdir..string_Pathsep.."*.*",wx.wxDIR)
|
||||
for i,dir in ipairs(dirs) do
|
||||
--DisplayOutput(dir.."\n")
|
||||
local dirs = FileSysGet(startdir..string_Pathsep.."*",wx.wxDIR)
|
||||
for _,dir in ipairs(dirs) do
|
||||
ProcInFiles(dir,mask,true,replace)
|
||||
end
|
||||
end
|
||||
|
||||
local files = FileSysGet(startdir..string_Pathsep..mask,wx.wxFILE)
|
||||
for i,file in ipairs(files) do
|
||||
findReplace.curfilename = file
|
||||
for _,file in ipairs(files) do
|
||||
-- ignore .bak files when replacing and asked to store .bak files
|
||||
if not (replace and findReplace.fMakeBak and file:find('.bak$')) then
|
||||
findReplace.curfilename = file
|
||||
|
||||
--DisplayOutput(file.."\n")
|
||||
local filetext = FileRead(file)
|
||||
if filetext then
|
||||
findReplace.oveditor:SetText(filetext)
|
||||
|
||||
-- load file
|
||||
local handle = io.open(file, "rb")
|
||||
if handle then
|
||||
local filetext = handle:read("*a")
|
||||
handle:close()
|
||||
findReplace.oveditor:SetText(filetext)
|
||||
|
||||
if (replace and findReplace:ReplaceString(true,onFileRegister)) then
|
||||
-- store changed content, make .bak
|
||||
if (findReplace.fMakeBak) then
|
||||
storefile(file..".bak",filetext)
|
||||
if replace then
|
||||
-- check if anything replaced, store changed content, make .bak
|
||||
if findReplace:ReplaceString(true,onFileRegister)
|
||||
and findReplace.fMakeBak and FileWrite(file..".bak",filetext) then
|
||||
FileWrite(file,findReplace.oveditor:GetText())
|
||||
end
|
||||
else
|
||||
findReplace:FindStringAll(onFileRegister)
|
||||
end
|
||||
storefile(file,findReplace.oveditor:GetText())
|
||||
else
|
||||
findReplace:FindStringAll(onFileRegister)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function findReplace:RunInFiles(replace)
|
||||
@@ -265,11 +253,12 @@ function findReplace:RunInFiles(replace)
|
||||
|
||||
local fname = wx.wxFileName(findReplace.filedirText)
|
||||
local startdir = findReplace.filedirText
|
||||
DisplayOutput("> FindInFiles "..(replace and "Replacing" or "Searching")..": '"..findReplace.findText.."'\n")
|
||||
DisplayOutput("FindInFiles: "..(replace and "Replacing" or "Searching for").." '"..findReplace.findText.."'.\n")
|
||||
|
||||
ProcInFiles(startdir, findReplace.filemaskText,findReplace.fSubDirs, replace)
|
||||
ProcInFiles(startdir, findReplace.filemaskText, findReplace.fSubDirs, replace)
|
||||
|
||||
DisplayOutput("> FindInFiles: "..findReplace.occurrences.." occurrence(s) have been found\n\n")
|
||||
DisplayOutput("FindInFiles: "..findReplace.occurrences.." instance(s) have been "..
|
||||
(replace and "replaced" or "found")..".\n")
|
||||
findReplace.oveditor = nil
|
||||
end
|
||||
|
||||
@@ -440,7 +429,7 @@ local function createFindReplaceDialog(replace,infiles)
|
||||
end
|
||||
|
||||
findDialog:Connect(ID_FIND_NEXT, wx.wxEVT_COMMAND_BUTTON_CLICKED,
|
||||
function(event)
|
||||
function()
|
||||
TransferDataFromWindow()
|
||||
if (findReplace.infiles) then
|
||||
findReplace:RunInFiles()
|
||||
@@ -479,8 +468,8 @@ local function createFindReplaceDialog(replace,infiles)
|
||||
|
||||
if infilesDirButton then
|
||||
findDialog:Connect(ID_SETDIR, wx.wxEVT_COMMAND_BUTTON_CLICKED,
|
||||
function(event)
|
||||
local filePicker = wx.wxDirDialog(findDialog, "Chose a project directory",
|
||||
function()
|
||||
local filePicker = wx.wxDirDialog(findDialog, "Choose a project directory",
|
||||
findReplace.filedirText~="" and findReplace.filedirText or wx.wxGetCwd(),wx.wxFLP_USE_TEXTCTRL)
|
||||
|
||||
local res = filePicker:ShowModal(true)
|
||||
|
||||
@@ -10,41 +10,23 @@ BREAKPOINT_MARKER_VALUE = 2 -- = 2^BREAKPOINT_MARKER
|
||||
CURRENT_LINE_MARKER = 2
|
||||
CURRENT_LINE_MARKER_VALUE = 4 -- = 2^CURRENT_LINE_MARKER
|
||||
|
||||
-- Globals
|
||||
local font = nil -- fonts to use for the editor
|
||||
local fontItalic = nil
|
||||
local ofont = nil -- fonts to use for the outputshell
|
||||
local ofontItalic = nil
|
||||
-- ----------------------------------------------------------------------------
|
||||
-- Pick some reasonable fixed width fonts to use for the editor
|
||||
if wx.__WXMSW__ then
|
||||
font = wx.wxFont(ide.config.editor.fontsize or 10, wx.wxFONTFAMILY_MODERN, wx.wxFONTSTYLE_NORMAL,
|
||||
wx.wxFONTWEIGHT_NORMAL, false, ide.config.editor.fontname or "Courier New", ide.config.editor.fontencoding or wx.wxFONTENCODING_DEFAULT)
|
||||
fontItalic = wx.wxFont(ide.config.editor.fontsize or 10, wx.wxFONTFAMILY_MODERN, wx.wxFONTSTYLE_ITALIC,
|
||||
wx.wxFONTWEIGHT_NORMAL, false, ide.config.editor.fontname or "Courier New", ide.config.editor.fontencoding or wx.wxFONTENCODING_DEFAULT)
|
||||
else
|
||||
font = wx.wxFont(ide.config.editor.fontsize or 10, wx.wxFONTFAMILY_MODERN, wx.wxFONTSTYLE_NORMAL,
|
||||
wx.wxFONTWEIGHT_NORMAL, false, ide.config.editor.fontname or "", ide.config.editor.fontencoding or wx.wxFONTENCODING_DEFAULT)
|
||||
fontItalic = wx.wxFont(ide.config.editor.fontsize or 10, wx.wxFONTFAMILY_MODERN, wx.wxFONTSTYLE_ITALIC,
|
||||
wx.wxFONTWEIGHT_NORMAL, false, ide.config.editor.fontname or "", ide.config.editor.fontencoding or wx.wxFONTENCODING_DEFAULT)
|
||||
local function setFont(style, config, name, size)
|
||||
return wx.wxFont(config.fontsize or size or 10, wx.wxFONTFAMILY_MODERN, style,
|
||||
wx.wxFONTWEIGHT_NORMAL, false, config.fontname or name,
|
||||
config.fontencoding or wx.wxFONTENCODING_DEFAULT)
|
||||
end
|
||||
ide.font.eNormal = setFont(wx.wxFONTSTYLE_NORMAL, ide.config.editor, wx.__WXMSW__ and "Courier New" or "")
|
||||
ide.font.eItalic = setFont(wx.wxFONTSTYLE_ITALIC, ide.config.editor, wx.__WXMSW__ and "Courier New" or "")
|
||||
|
||||
if wx.__WXMSW__ then
|
||||
ofont = wx.wxFont(ide.config.outputshell.fontsize or 10, wx.wxFONTFAMILY_MODERN, wx.wxFONTSTYLE_NORMAL,
|
||||
wx.wxFONTWEIGHT_NORMAL, false, ide.config.outputshell.fontname or "Courier New", ide.config.outputshell.fontencoding or wx.wxFONTENCODING_DEFAULT)
|
||||
ofontItalic = wx.wxFont(ide.config.outputshell.fontsize or 10, wx.wxFONTFAMILY_MODERN, wx.wxFONTSTYLE_ITALIC,
|
||||
wx.wxFONTWEIGHT_NORMAL, false, ide.config.outputshell.fontname or "Courier New", ide.config.outputshell.fontencoding or wx.wxFONTENCODING_DEFAULT)
|
||||
else
|
||||
ofont = wx.wxFont(ide.config.outputshell.fontsize or 10, wx.wxFONTFAMILY_MODERN, wx.wxFONTSTYLE_NORMAL,
|
||||
wx.wxFONTWEIGHT_NORMAL, false, ide.config.outputshell.fontname or "", ide.config.outputshell.fontencoding or wx.wxFONTENCODING_DEFAULT)
|
||||
ofontItalic = wx.wxFont(ide.config.outputshell.fontsize or 10, wx.wxFONTFAMILY_MODERN, wx.wxFONTSTYLE_ITALIC,
|
||||
wx.wxFONTWEIGHT_NORMAL, false, ide.config.outputshell.fontname or "", ide.config.outputshell.fontencoding or wx.wxFONTENCODING_DEFAULT)
|
||||
end
|
||||
ide.font.oNormal = setFont(wx.wxFONTSTYLE_NORMAL, ide.config.outputshell, wx.__WXMSW__ and "Courier New" or "")
|
||||
ide.font.oItalic = setFont(wx.wxFONTSTYLE_ITALIC, ide.config.outputshell, wx.__WXMSW__ and "Courier New" or "")
|
||||
|
||||
ide.font = font
|
||||
ide.fontItalic = fontItalic
|
||||
ide.ofont = ofont
|
||||
ide.ofontItalic = ofontItalic
|
||||
-- treeCtrl font requires slightly different handling
|
||||
local gui, config = wx.wxTreeCtrl():GetFont(), ide.config.filetree
|
||||
if config.fontsize then gui:SetPointSize(config.fontsize) end
|
||||
if config.fontname then gui:SetFaceName(config.fontname) end
|
||||
ide.font.fNormal = gui
|
||||
|
||||
-- ----------------------------------------------------------------------------
|
||||
-- Create the wxFrame
|
||||
@@ -65,18 +47,21 @@ local function createFrame()
|
||||
end)
|
||||
|
||||
local menuBar = wx.wxMenuBar()
|
||||
frame.menuBar = menuBar
|
||||
|
||||
local statusBar = frame:CreateStatusBar( 5 )
|
||||
frame.statusBar = statusBar
|
||||
local status_txt_width = statusBar:GetTextExtent("OVRW")
|
||||
statusBar:SetStatusWidths({-1, status_txt_width*6, status_txt_width, status_txt_width, status_txt_width*5})
|
||||
local statusBar = frame:CreateStatusBar(6)
|
||||
local section_width = statusBar:GetTextExtent("OVRW")
|
||||
statusBar:SetStatusStyles({wx.wxSB_RAISED, wx.wxSB_RAISED, wx.wxSB_RAISED,
|
||||
wx.wxSB_RAISED, wx.wxSB_RAISED, wx.wxSB_RAISED})
|
||||
statusBar:SetStatusWidths(
|
||||
{-1, section_width*6, section_width, section_width, section_width*4, section_width*4})
|
||||
statusBar:SetStatusText(GetIDEString("statuswelcome"))
|
||||
|
||||
local mgr = wxaui.wxAuiManager()
|
||||
frame.uimgr = mgr
|
||||
mgr:SetManagedWindow(frame)
|
||||
|
||||
frame.menuBar = menuBar
|
||||
frame.statusBar = statusBar
|
||||
frame.uimgr = mgr
|
||||
|
||||
return frame
|
||||
end
|
||||
|
||||
@@ -86,23 +71,24 @@ local function createToolBar(frame)
|
||||
local funclist = wx.wxChoice.new(toolBar,ID "toolBar.funclist",wx.wxDefaultPosition, wx.wxSize.new(240,16))
|
||||
|
||||
-- note: Ususally the bmp size isn't necessary, but the HELP icon is not the right size in MSW
|
||||
local getBitmap = (ide.app.createbitmap or wx.wxArtProvider.GetBitmap)
|
||||
local toolBmpSize = toolBar:GetToolBitmapSize()
|
||||
toolBar:AddTool(ID_NEW, "New", wx.wxArtProvider.GetBitmap(wx.wxART_NORMAL_FILE, wx.wxART_TOOLBAR, toolBmpSize), "Create an empty document")
|
||||
toolBar:AddTool(ID_OPEN, "Open", wx.wxArtProvider.GetBitmap(wx.wxART_FILE_OPEN, wx.wxART_TOOLBAR, toolBmpSize), "Open an existing document")
|
||||
toolBar:AddTool(ID_SAVE, "Save", wx.wxArtProvider.GetBitmap(wx.wxART_FILE_SAVE, wx.wxART_TOOLBAR, toolBmpSize), "Save the current document")
|
||||
toolBar:AddTool(ID_SAVEALL, "Save All", wx.wxArtProvider.GetBitmap(wx.wxART_NEW_DIR, wx.wxART_TOOLBAR, toolBmpSize), "Save all documents")
|
||||
toolBar:AddTool(ID_NEW, "New", getBitmap(wx.wxART_NORMAL_FILE, wx.wxART_TOOLBAR, toolBmpSize), "Create an empty document")
|
||||
toolBar:AddTool(ID_OPEN, "Open", getBitmap(wx.wxART_FILE_OPEN, wx.wxART_TOOLBAR, toolBmpSize), "Open an existing document")
|
||||
toolBar:AddTool(ID_SAVE, "Save", getBitmap(wx.wxART_FILE_SAVE, wx.wxART_TOOLBAR, toolBmpSize), "Save the current document")
|
||||
toolBar:AddTool(ID_SAVEALL, "Save All", getBitmap(wx.wxART_NEW_DIR, wx.wxART_TOOLBAR, toolBmpSize), "Save all documents")
|
||||
toolBar:AddSeparator()
|
||||
toolBar:AddTool(ID_CUT, "Cut", wx.wxArtProvider.GetBitmap(wx.wxART_CUT, wx.wxART_TOOLBAR, toolBmpSize), "Cut the selection")
|
||||
toolBar:AddTool(ID_COPY, "Copy", wx.wxArtProvider.GetBitmap(wx.wxART_COPY, wx.wxART_TOOLBAR, toolBmpSize), "Copy the selection")
|
||||
toolBar:AddTool(ID_PASTE, "Paste", wx.wxArtProvider.GetBitmap(wx.wxART_PASTE, wx.wxART_TOOLBAR, toolBmpSize), "Paste text from the clipboard")
|
||||
toolBar:AddTool(ID_CUT, "Cut", getBitmap(wx.wxART_CUT, wx.wxART_TOOLBAR, toolBmpSize), "Cut the selection")
|
||||
toolBar:AddTool(ID_COPY, "Copy", getBitmap(wx.wxART_COPY, wx.wxART_TOOLBAR, toolBmpSize), "Copy the selection")
|
||||
toolBar:AddTool(ID_PASTE, "Paste", getBitmap(wx.wxART_PASTE, wx.wxART_TOOLBAR, toolBmpSize), "Paste text from the clipboard")
|
||||
toolBar:AddSeparator()
|
||||
toolBar:AddTool(ID_UNDO, "Undo", wx.wxArtProvider.GetBitmap(wx.wxART_UNDO, wx.wxART_TOOLBAR, toolBmpSize), "Undo last edit")
|
||||
toolBar:AddTool(ID_REDO, "Redo", wx.wxArtProvider.GetBitmap(wx.wxART_REDO, wx.wxART_TOOLBAR, toolBmpSize), "Redo last undo")
|
||||
toolBar:AddTool(ID_UNDO, "Undo", getBitmap(wx.wxART_UNDO, wx.wxART_TOOLBAR, toolBmpSize), "Undo last edit")
|
||||
toolBar:AddTool(ID_REDO, "Redo", getBitmap(wx.wxART_REDO, wx.wxART_TOOLBAR, toolBmpSize), "Redo last undo")
|
||||
toolBar:AddSeparator()
|
||||
toolBar:AddTool(ID_FIND, "Find", wx.wxArtProvider.GetBitmap(wx.wxART_FIND, wx.wxART_TOOLBAR, toolBmpSize), "Find text")
|
||||
toolBar:AddTool(ID_REPLACE, "Replace", wx.wxArtProvider.GetBitmap(wx.wxART_FIND_AND_REPLACE, wx.wxART_TOOLBAR, toolBmpSize), "Find and replace text")
|
||||
toolBar:AddTool(ID_FIND, "Find", getBitmap(wx.wxART_FIND, wx.wxART_TOOLBAR, toolBmpSize), "Find text")
|
||||
toolBar:AddTool(ID_REPLACE, "Replace", getBitmap(wx.wxART_FIND_AND_REPLACE, wx.wxART_TOOLBAR, toolBmpSize), "Find and replace text")
|
||||
toolBar:AddSeparator()
|
||||
toolBar:AddTool(ID "debug.projectdir.fromfile", "Update", wx.wxArtProvider.GetBitmap(wx.wxART_GO_DIR_UP , wx.wxART_TOOLBAR, toolBmpSize), "Sets projectdir from file")
|
||||
toolBar:AddTool(ID "debug.projectdir.fromfile", "Update", getBitmap(wx.wxART_GO_DIR_UP , wx.wxART_TOOLBAR, toolBmpSize), "Sets projectdir from file")
|
||||
toolBar:AddSeparator()
|
||||
toolBar:AddControl(funclist)
|
||||
toolBar:Realize()
|
||||
|
||||
@@ -53,6 +53,7 @@ ID_BREAK = NewID()
|
||||
ID_TRACE = NewID()
|
||||
ID_VIEWCALLSTACK = NewID()
|
||||
ID_VIEWWATCHWINDOW = NewID()
|
||||
ID_FULLSCREEN = NewID()
|
||||
ID_CLEAROUTPUT = NewID()
|
||||
ID_PROJECTDIR = NewID()
|
||||
ID_INTERPRETER = NewID()
|
||||
|
||||
@@ -66,11 +66,16 @@ function M.show_warnings(top_ast)
|
||||
if name ~= 'self' then
|
||||
local func = parent.parent and parent.parent.parent
|
||||
local assignment = not func.tag or func.tag == 'Set' or func.tag == 'Localrec'
|
||||
local fname = assignment and type(func[1][1][1]) == 'string' and func[1][1][1]
|
||||
local func1 = func[1][1]
|
||||
local fname = assignment and func1 and type(func1[1]) == 'string' and func1[1]
|
||||
or (func1.tag == 'Index' and func1[1][1] .. '.' .. func1[2][1])
|
||||
-- "function foo(bar)" => func.tag == 'Set'
|
||||
-- `Set{{`Id{"foo"}},{`Function{{`Id{"bar"}},{}}}}
|
||||
-- "local function foo(bar)" => func.tag == 'Localrec'
|
||||
-- "local _, foo = 1, function(bar)" => func.tag == 'Local'
|
||||
-- "print(function(bar) end)" => func.tag == nil
|
||||
-- "function tbl:foo(bar)" => func.tag == 'Set'
|
||||
-- `Set{{`Index{`Id{"tbl"},`String{"foo"}}},{`Function{{`Id{"self"},`Id{"bar"}},{}}}}
|
||||
warn("unused parameter '" .. name .. "'" ..
|
||||
(func and assignment
|
||||
and (fname and func.tag
|
||||
|
||||
@@ -46,10 +46,20 @@ ide.iofilters["GermanUtf8Ascii"] = {
|
||||
|
||||
}
|
||||
|
||||
ide.iofilters["0d0d0aFix"] = {
|
||||
-- this function converts 0d0d0a line ending to 0d0a
|
||||
input = function(fpath, content)
|
||||
return content:gsub("\013\013\010","\013\010")
|
||||
end,
|
||||
}
|
||||
|
||||
--üäß
|
||||
|
||||
for i,filter in pairs(ide.iofilters) do
|
||||
assert(filter.output("",filter.input("","äöüÄÖÜß")),"„â€ÂäöüÄÖÜß","UTF8-ANSI conversion failed: "..(i))
|
||||
if filter.input and filter.output then
|
||||
assert(filter.output("",filter.input("","äöüÄÖÜß")),
|
||||
"„â€ÂäöüÄÖÜß","UTF8-ANSI conversion failed: "..(i))
|
||||
end
|
||||
end
|
||||
|
||||
-- which: "input" or "output"
|
||||
|
||||
@@ -5,12 +5,13 @@ local styles = ide.config.styles
|
||||
local comment = styles.comment
|
||||
local MD_MARK_ITAL = '_' -- italic
|
||||
local MD_MARK_BOLD = '**' -- bold
|
||||
local MD_MARK_LINK = '[' -- link
|
||||
local MD_MARK_LINT = ')' -- link terminator
|
||||
local MD_MARK_LINK = '[' -- link description start
|
||||
local MD_MARK_LINZ = ']' -- link description end
|
||||
local MD_MARK_LINA = '(' -- link URL start
|
||||
local MD_MARK_LINT = ')' -- link URL end
|
||||
local MD_MARK_HEAD = '#' -- header
|
||||
local MD_MARK_CODE = '`' -- code
|
||||
local MD_MARK_BOXD = '|' -- highlight
|
||||
local MD_MARK_LSEP = '](' -- link separator (between text and link)
|
||||
local MD_MARK_MARK = ' ' -- separator
|
||||
local MD_LINK_NEWWINDOW = '+' -- indicator to open a new window for links
|
||||
local markup = {
|
||||
@@ -45,11 +46,12 @@ function MarkupHotspotClick(pos, editor)
|
||||
pos = pos + #MD_MARK_LINK - editor:PositionFromLine(line) -- turn into relative position
|
||||
|
||||
-- extract the URL/command on the right side of the separator
|
||||
local _,_,text = string.find(tx, q(MD_MARK_LSEP).."([^%s]+)"..q(MD_MARK_LINT), pos)
|
||||
local _,_,text = string.find(tx, q(MD_MARK_LINZ).."(%b"..MD_MARK_LINA..MD_MARK_LINT..")", pos)
|
||||
if text then
|
||||
text = text:gsub("^"..q(MD_MARK_LINA), ""):gsub(q(MD_MARK_LINT).."$", "")
|
||||
local filepath = ide.openDocuments[editor:GetId()].filePath
|
||||
local _,_,shell = string.find(text, [[^macro:shell%((.*%S)%)$]])
|
||||
local _,_,http = string.find(text, [[^(http:%S+)$]])
|
||||
local _,_,http = string.find(text, [[^(https?:%S+)$]])
|
||||
local _,_,command = string.find(text, [[^macro:(%w+)$]])
|
||||
if shell then
|
||||
ShellExecuteCode(shell)
|
||||
@@ -59,7 +61,7 @@ function MarkupHotspotClick(pos, editor)
|
||||
ProjectDebug()
|
||||
elseif http then -- open the URL in a new browser window
|
||||
wx.wxLaunchDefaultBrowser(http, 0)
|
||||
else
|
||||
elseif filepath then -- only check for saved files
|
||||
-- check if requested to open in a new window
|
||||
local newwindow = string.find(text, MD_LINK_NEWWINDOW, 1, true) -- plain search
|
||||
if newwindow then text = string.gsub(text, "^%" .. MD_LINK_NEWWINDOW, "") end
|
||||
@@ -70,6 +72,7 @@ function MarkupHotspotClick(pos, editor)
|
||||
filename:Normalize() -- remove .., ., and other similar elements
|
||||
if filename:FileExists() and
|
||||
(newwindow or SaveModifiedDialog(editor, true) ~= wx.wxID_CANCEL) then
|
||||
if not newwindow and ide.osname == 'Macintosh' then editor:GotoPos(0) end
|
||||
LoadFile(filename,not newwindow and editor or nil,true)
|
||||
end
|
||||
end
|
||||
@@ -96,10 +99,10 @@ local function ismarkup (tx)
|
||||
-- [%w%p] set is needed to avoid continuing this markup to the next line
|
||||
s,e,cap = string.find(tx,"^("..q(MD_MARK_HEAD)..".+[%w%p])")
|
||||
elseif sep == MD_MARK_LINK then
|
||||
-- allow everything except spaces in the second part
|
||||
s,e,cap = string.find(tx,"^("..q(MD_MARK_LINK)..nonspace..".-"..nonspace
|
||||
..q(MD_MARK_LSEP).."[^%s]+"
|
||||
..q(MD_MARK_LINT)..")", st)
|
||||
-- allow everything based on balanced link separators
|
||||
s,e,cap = string.find(tx,
|
||||
"^(%b"..MD_MARK_LINK..MD_MARK_LINZ
|
||||
.."%b"..MD_MARK_LINA..MD_MARK_LINT..")", st)
|
||||
elseif markup[sep] then
|
||||
-- try 2+ characters between separators first
|
||||
-- if not found, try a single character
|
||||
@@ -144,7 +147,9 @@ function MarkupStyle(editor, lines, linee)
|
||||
if (f) then
|
||||
local p = ls+f+off
|
||||
local s = bit.band(editor:GetStyleAt(p), 31)
|
||||
if iscomment[s] then
|
||||
-- only style comments and only those that are not at the beginning
|
||||
-- of the file to avoid styling shebang (#!) lines
|
||||
if iscomment[s] and p > 0 then
|
||||
local smark = #mark
|
||||
local emark = #mark -- assumes end mark is the same length as start mark
|
||||
if mark == MD_MARK_HEAD then
|
||||
@@ -152,7 +157,7 @@ function MarkupStyle(editor, lines, linee)
|
||||
local _,_,full = string.find(w,"^("..q(MD_MARK_HEAD).."+)")
|
||||
smark,emark = #full,0
|
||||
elseif mark == MD_MARK_LINK then
|
||||
local lsep = w:find(q(MD_MARK_LSEP))
|
||||
local lsep = w:find(q(MD_MARK_LINZ)..q(MD_MARK_LINA))
|
||||
if lsep then emark = #w-lsep+#MD_MARK_LINT end
|
||||
end
|
||||
editor:StartStyling(p, 31)
|
||||
|
||||
@@ -30,21 +30,46 @@ menuBar:Append(editMenu, "&Edit")
|
||||
|
||||
editMenu:Check(ID_AUTOCOMPLETE_ENABLE, ide.config.autocomplete)
|
||||
|
||||
function OnUpdateUIEditMenu(event) -- enable if there is a valid focused editor
|
||||
local function getControlWithFocus()
|
||||
local editor = GetEditor()
|
||||
event:Enable(editor ~= nil)
|
||||
for _,e in pairs({frame.bottomnotebook.shellbox, frame.bottomnotebook.errorlog}) do
|
||||
local ctrl = e:FindFocus()
|
||||
if ctrl and
|
||||
(ctrl:GetId() == e:GetId()
|
||||
or ide.osname == 'Macintosh' and
|
||||
ctrl:GetParent():GetId() == e:GetId()) then editor = e end
|
||||
end
|
||||
return editor
|
||||
end
|
||||
|
||||
local othereditors = { frame.bottomnotebook.shellbox, frame.bottomnotebook.errorlog }
|
||||
function OnUpdateUIEditMenu(event)
|
||||
local editor = getControlWithFocus()
|
||||
if editor == nil then event:Enable(false); return end
|
||||
|
||||
local menu_id = event:GetId()
|
||||
local enable =
|
||||
-- buggy GTK clipboard runs eventloop and can generate asserts
|
||||
menu_id == ID_PASTE and (wx.__WXGTK__ or editor:CanPaste()) or
|
||||
menu_id == ID_UNDO and editor:CanUndo() or
|
||||
menu_id == ID_REDO and editor:CanRedo() or
|
||||
(menu_id ~= ID_PASTE and menu_id ~= ID_UNDO and menu_id ~= ID_REDO)
|
||||
-- wxComboBox doesn't have SELECT ALL, so disable it
|
||||
if editor:GetClassInfo():GetClassName() == 'wxComboBox'
|
||||
and menu_id == ID_SELECTALL then enable = false end
|
||||
event:Enable(enable)
|
||||
end
|
||||
|
||||
function OnEditMenu(event)
|
||||
local menu_id = event:GetId()
|
||||
local editor = GetEditor()
|
||||
for _,e in pairs(othereditors) do
|
||||
if e:FindFocus():GetId() == e:GetId() then editor = e end
|
||||
end
|
||||
if editor == nil then return end
|
||||
local editor = getControlWithFocus()
|
||||
|
||||
-- if there is no editor, or if it's not the editor we care about,
|
||||
-- then allow normal processing to take place
|
||||
if editor == nil or
|
||||
editor:FindFocus():GetId() ~= editor:GetId() or
|
||||
editor:GetClassInfo():GetClassName() ~= 'wxStyledTextCtrl'
|
||||
then event:Skip(); return end
|
||||
|
||||
local menu_id = event:GetId()
|
||||
if menu_id == ID_CUT then editor:Cut()
|
||||
elseif menu_id == ID_COPY then editor:Copy()
|
||||
elseif menu_id == ID_PASTE then editor:Paste()
|
||||
@@ -54,36 +79,10 @@ function OnEditMenu(event)
|
||||
end
|
||||
end
|
||||
|
||||
frame:Connect(ID_CUT, wx.wxEVT_COMMAND_MENU_SELECTED, OnEditMenu)
|
||||
frame:Connect(ID_CUT, wx.wxEVT_UPDATE_UI, OnUpdateUIEditMenu)
|
||||
|
||||
frame:Connect(ID_COPY, wx.wxEVT_COMMAND_MENU_SELECTED, OnEditMenu)
|
||||
frame:Connect(ID_COPY, wx.wxEVT_UPDATE_UI, OnUpdateUIEditMenu)
|
||||
|
||||
frame:Connect(ID_PASTE, wx.wxEVT_COMMAND_MENU_SELECTED, OnEditMenu)
|
||||
frame:Connect(ID_PASTE, wx.wxEVT_UPDATE_UI,
|
||||
function (event)
|
||||
local editor = GetEditor()
|
||||
-- buggy GTK clipboard runs eventloop and can generate asserts
|
||||
event:Enable(editor and (wx.__WXGTK__ or editor:CanPaste()))
|
||||
end)
|
||||
|
||||
frame:Connect(ID_SELECTALL, wx.wxEVT_COMMAND_MENU_SELECTED, OnEditMenu)
|
||||
frame:Connect(ID_SELECTALL, wx.wxEVT_UPDATE_UI, OnUpdateUIEditMenu)
|
||||
|
||||
frame:Connect(ID_UNDO, wx.wxEVT_COMMAND_MENU_SELECTED, OnEditMenu)
|
||||
frame:Connect(ID_UNDO, wx.wxEVT_UPDATE_UI,
|
||||
function (event)
|
||||
local editor = GetEditor()
|
||||
event:Enable(editor and editor:CanUndo())
|
||||
end)
|
||||
|
||||
frame:Connect(ID_REDO, wx.wxEVT_COMMAND_MENU_SELECTED, OnEditMenu)
|
||||
frame:Connect(ID_REDO, wx.wxEVT_UPDATE_UI,
|
||||
function (event)
|
||||
local editor = GetEditor()
|
||||
event:Enable(editor and editor:CanRedo())
|
||||
end)
|
||||
for _, event in pairs({ID_CUT, ID_COPY, ID_PASTE, ID_SELECTALL, ID_UNDO, ID_REDO}) do
|
||||
frame:Connect(event, wx.wxEVT_COMMAND_MENU_SELECTED, OnEditMenu)
|
||||
frame:Connect(event, wx.wxEVT_UPDATE_UI, OnUpdateUIEditMenu)
|
||||
end
|
||||
|
||||
frame:Connect(ID "edit.cleardynamics", wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
function (event)
|
||||
@@ -93,54 +92,18 @@ frame:Connect(ID "edit.cleardynamics", wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
frame:Connect(ID "edit.showtooltip", wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
function (event)
|
||||
local editor = GetEditor()
|
||||
local pos = editor:GetCurrentPos()
|
||||
local line = editor:GetCurrentLine()
|
||||
local linetx = editor:GetLine(line)
|
||||
local linestart = editor:PositionFromLine(line)
|
||||
local localpos = pos-linestart
|
||||
|
||||
local linetxtopos = linetx:sub(1,localpos)
|
||||
linetxtopos = linetxtopos..")"
|
||||
linetxtopos = linetxtopos:match("([a-zA-Z_0-9%.%:]+)%b()$")
|
||||
|
||||
local tip = linetxtopos and GetTipInfo(editor,linetxtopos.."(",false)
|
||||
if tip then
|
||||
if(editor:CallTipActive()) then
|
||||
editor:CallTipCancel()
|
||||
end
|
||||
editor:CallTipShow(pos,tip)
|
||||
if (editor:CallTipActive()) then
|
||||
editor:CallTipCancel()
|
||||
return
|
||||
end
|
||||
|
||||
EditorCallTip(editor, editor:GetCurrentPos())
|
||||
end)
|
||||
|
||||
frame:Connect(ID_AUTOCOMPLETE, wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
function (event)
|
||||
local editor = GetEditor()
|
||||
if (editor == nil or not editor.spec) then return end
|
||||
|
||||
-- retrieve the current line and get a string to the current cursor position in the line
|
||||
local pos = editor:GetCurrentPos()
|
||||
local line = editor:GetCurrentLine()
|
||||
local linetx = editor:GetLine(line)
|
||||
local linestart = editor:PositionFromLine(line)
|
||||
local localpos = pos-linestart
|
||||
|
||||
local lt = linetx:sub(1,localpos)
|
||||
lt = lt:gsub("%s*("..editor.spec.sep..")%s*",function(a) return a end)
|
||||
lt = lt:gsub("%s*%b[]%s*","")
|
||||
lt = lt:gsub("%s*%b()%s*","")
|
||||
lt = lt:gsub("%s*%b{}%s*","")
|
||||
lt = lt:match("[^%[%(%s]*$")
|
||||
lt = lt:gsub("%s","")
|
||||
|
||||
-- know now which string is to be completed
|
||||
|
||||
local userList = CreateAutoCompList(editor,lt)
|
||||
if userList and string.len(userList) > 0 then
|
||||
editor:UserListShow(1, userList)
|
||||
--ShowList(userList)
|
||||
elseif (editor:AutoCompActive()) then
|
||||
editor:AutoCompCancel()
|
||||
end
|
||||
EditorAutoComplete(GetEditor())
|
||||
end)
|
||||
frame:Connect(ID_AUTOCOMPLETE, wx.wxEVT_UPDATE_UI, OnUpdateUIEditMenu)
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ local ide = ide
|
||||
local frame = ide.frame
|
||||
local menuBar = frame.menuBar
|
||||
local openDocuments = ide.openDocuments
|
||||
local debugger = ide.debugger
|
||||
|
||||
local fileMenu = wx.wxMenu({
|
||||
{ ID_NEW, "&New\tCtrl-N", "Create an empty document" },
|
||||
|
||||
@@ -49,9 +49,9 @@ local debugTab = {
|
||||
{ ID_ATTACH_DEBUG, "&Start Debugger Server", "Allow a client to start a debugging session" },
|
||||
{ },
|
||||
{ ID_STOP_DEBUG, "S&top Debugging\tShift-F12", "Stop the currently running process" },
|
||||
{ ID_STEP, "St&ep\tF11", "Step into the next line" },
|
||||
{ ID_STEP_OVER, "Step &Over\tF10", "Step over the next line" },
|
||||
{ ID_STEP_OUT, "Step O&ut\tShift-F10", "Step out of the current function" },
|
||||
{ ID_STEP, "Step &Into\tF10", "Step into the next line" },
|
||||
{ ID_STEP_OVER, "Step &Over\tShift-F10", "Step over the next line" },
|
||||
{ ID_STEP_OUT, "Step O&ut\tCtrl-F10", "Step out of the current function" },
|
||||
{ ID_TRACE, "Tr&ace", "Trace execution showing each executed line" },
|
||||
{ ID_BREAK, "&Break\tShift-F9", "Stop execution of the program at the next executed line of code" },
|
||||
{ },
|
||||
@@ -62,7 +62,7 @@ local debugTab = {
|
||||
|
||||
local debugMenu = wx.wxMenu(debugTab)
|
||||
local debugMenuRun = {start="Start &Debugging\tF5", continue="Co&ntinue\tF5"}
|
||||
local debugMenuStop = {debugging="S&top Debugging\tShift-F12", process="S&top Process\tShift-F12"}
|
||||
local debugMenuStop = {debugging="S&top Debugging\tShift-F5", process="S&top Process\tShift-F5"}
|
||||
|
||||
local targetDirMenu = wx.wxMenu{
|
||||
{ID "debug.projectdir.choose","Choose ..."},
|
||||
@@ -129,11 +129,17 @@ frame:Connect(ID "debug.projectdir.fromfile", wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
-- Interpreter Selection and Running
|
||||
|
||||
local function selectInterpreter(id)
|
||||
for i,inter in pairs(interpreters) do
|
||||
menuBar:Check(i, false)
|
||||
for id in pairs(interpreters) do
|
||||
menuBar:Check(id, false)
|
||||
menuBar:Enable(id, true)
|
||||
end
|
||||
menuBar:Check(id, true)
|
||||
menuBar:Enable(id, false)
|
||||
|
||||
ide.interpreter = interpreters[id]
|
||||
|
||||
if DebuggerShutdown then DebuggerShutdown() end
|
||||
ide.frame.statusBar:SetStatusText(ide.interpreter.name or "", 5)
|
||||
ReloadLuaAPI()
|
||||
end
|
||||
|
||||
@@ -143,9 +149,8 @@ function ProjectSetInterpreter(name)
|
||||
selectInterpreter(id)
|
||||
end
|
||||
|
||||
local function evSelectInterpreter (event)
|
||||
local chose = event:GetId()
|
||||
selectInterpreter(chose)
|
||||
local function evSelectInterpreter(event)
|
||||
selectInterpreter(event:GetId())
|
||||
end
|
||||
|
||||
for id,inter in pairs(interpreters) do
|
||||
@@ -203,8 +208,7 @@ end
|
||||
function ProjectRun(skipcheck)
|
||||
local fname = getNameToRun(skipcheck)
|
||||
if not fname then return end
|
||||
runInterpreter(fname)
|
||||
return true
|
||||
return runInterpreter(fname)
|
||||
end
|
||||
|
||||
local debuggers = {
|
||||
@@ -223,7 +227,7 @@ function ProjectDebug(skipcheck, debtype)
|
||||
format(ide.debugger.hostname, ide.debugger.portnumber)
|
||||
local fname = getNameToRun(skipcheck)
|
||||
if not fname then return end
|
||||
runInterpreter(fname, debcall)
|
||||
return runInterpreter(fname, debcall) -- this may be pid or nil
|
||||
end
|
||||
return true
|
||||
end
|
||||
@@ -282,7 +286,6 @@ frame:Connect(ID_RUNNOW, wx.wxEVT_UPDATE_UI,
|
||||
|
||||
frame:Connect(ID_ATTACH_DEBUG, wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
function (event)
|
||||
ClearAllCurrentLineMarkers()
|
||||
if (ide.interpreter.fattachdebug) then ide.interpreter:fattachdebug() end
|
||||
end)
|
||||
frame:Connect(ID_ATTACH_DEBUG, wx.wxEVT_UPDATE_UI,
|
||||
@@ -310,7 +313,6 @@ frame:Connect(ID_START_DEBUG, wx.wxEVT_UPDATE_UI,
|
||||
|
||||
frame:Connect(ID_STOP_DEBUG, wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
function (event)
|
||||
ClearAllCurrentLineMarkers()
|
||||
DebuggerShutdown()
|
||||
end)
|
||||
frame:Connect(ID_STOP_DEBUG, wx.wxEVT_UPDATE_UI,
|
||||
|
||||
@@ -23,33 +23,35 @@ local findMenu = wx.wxMenu{
|
||||
{ ID_SORT, "&Sort", "Sort selected lines"}}
|
||||
menuBar:Append(findMenu, "&Search")
|
||||
|
||||
function OnUpdateUISearchMenu(event) event:Enable(GetEditor() ~= nil) end
|
||||
|
||||
frame:Connect(ID_FIND, wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
function (event)
|
||||
findReplace:GetSelectedString()
|
||||
findReplace:Show(false)
|
||||
end)
|
||||
frame:Connect(ID_FIND, wx.wxEVT_UPDATE_UI, OnUpdateUIEditMenu)
|
||||
frame:Connect(ID_FIND, wx.wxEVT_UPDATE_UI, OnUpdateUISearchMenu)
|
||||
|
||||
frame:Connect(ID_REPLACE, wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
function (event)
|
||||
findReplace:GetSelectedString()
|
||||
findReplace:Show(true)
|
||||
end)
|
||||
frame:Connect(ID_REPLACE, wx.wxEVT_UPDATE_UI, OnUpdateUIEditMenu)
|
||||
frame:Connect(ID_REPLACE, wx.wxEVT_UPDATE_UI, OnUpdateUISearchMenu)
|
||||
|
||||
frame:Connect(ID_FIND_IN_FILES, wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
function (event)
|
||||
findReplace:GetSelectedString()
|
||||
findReplace:Show(false,true)
|
||||
end)
|
||||
frame:Connect(ID_FIND_IN_FILES, wx.wxEVT_UPDATE_UI, OnUpdateUIEditMenu)
|
||||
frame:Connect(ID_FIND_IN_FILES, wx.wxEVT_UPDATE_UI, OnUpdateUISearchMenu)
|
||||
|
||||
frame:Connect(ID_REPLACE_IN_FILES, wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
function (event)
|
||||
findReplace:GetSelectedString()
|
||||
findReplace:Show(true,true)
|
||||
end)
|
||||
frame:Connect(ID_REPLACE_IN_FILES, wx.wxEVT_UPDATE_UI, OnUpdateUIEditMenu)
|
||||
frame:Connect(ID_REPLACE_IN_FILES, wx.wxEVT_UPDATE_UI, OnUpdateUISearchMenu)
|
||||
|
||||
frame:Connect(ID_FINDNEXT, wx.wxEVT_COMMAND_MENU_SELECTED, function (event) findReplace:GetSelectedString() findReplace:FindString() end)
|
||||
frame:Connect(ID_FINDNEXT, wx.wxEVT_UPDATE_UI, function (event) findReplace:HasText() end)
|
||||
@@ -73,7 +75,7 @@ frame:Connect(ID_GOTOLINE, wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
editor:GotoLine(linenum-1)
|
||||
end
|
||||
end)
|
||||
frame:Connect(ID_GOTOLINE, wx.wxEVT_UPDATE_UI, OnUpdateUIEditMenu)
|
||||
frame:Connect(ID_GOTOLINE, wx.wxEVT_UPDATE_UI, OnUpdateUISearchMenu)
|
||||
|
||||
frame:Connect(ID_SORT, wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
function (event)
|
||||
@@ -87,4 +89,4 @@ frame:Connect(ID_SORT, wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
editor:ReplaceSelection(table.concat(buf,"\n"))
|
||||
end
|
||||
end)
|
||||
frame:Connect(ID_SORT, wx.wxEVT_UPDATE_UI, OnUpdateUIEditMenu)
|
||||
frame:Connect(ID_SORT, wx.wxEVT_UPDATE_UI, OnUpdateUISearchMenu)
|
||||
|
||||
@@ -6,9 +6,7 @@ local frame = ide.frame
|
||||
local menuBar = frame.menuBar
|
||||
local uimgr = frame.uimgr
|
||||
|
||||
local debugger = ide.debugger
|
||||
|
||||
local viewMenu = wx.wxMenu{
|
||||
local viewMenu = wx.wxMenu {
|
||||
-- NYI { ID "view.preferences", "&Preferences...", "Brings up dialog for settings (TODO)" },
|
||||
-- NYI { },
|
||||
{ ID "view.filetree.show", "Project/&FileTree Window\tCtrl-Shift-P", "View the project/filetree window" },
|
||||
@@ -17,7 +15,7 @@ local viewMenu = wx.wxMenu{
|
||||
{ ID_VIEWCALLSTACK, "&Stack Window\tCtrl-Shift-S", "View the Stack window" },
|
||||
{ },
|
||||
{ ID "view.defaultlayout", "&Default Layout", "Reset to default layout"},
|
||||
{ ID "view.fullscreen", "Full &Screen\tCtrl-Shift-A", "Switch to or from full screen mode"},
|
||||
{ ID_FULLSCREEN, "Full &Screen\tCtrl-Shift-A", "Switch to or from full screen mode"},
|
||||
{ ID "view.style.loadconfig", "&Load Config Style...", "Load and apply style from config file (must contain .styles)"},
|
||||
}
|
||||
menuBar:Append(viewMenu, "&View")
|
||||
@@ -47,8 +45,9 @@ frame:Connect(ID "view.filetree.show", wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
uimgr:Update()
|
||||
end)
|
||||
|
||||
frame:Connect(ID "view.fullscreen", wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
function (event) ShowFullScreen(not frame:IsFullScreen()) end)
|
||||
frame:Connect(ID_FULLSCREEN, wx.wxEVT_COMMAND_MENU_SELECTED, function ()
|
||||
pcall(function() ShowFullScreen(not frame:IsFullScreen()) end)
|
||||
end)
|
||||
|
||||
frame:Connect(ID_VIEWWATCHWINDOW, wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
function (event) DebuggerCreateWatchWindow() end)
|
||||
|
||||
@@ -13,8 +13,8 @@ local INPUT_MARKER = 3
|
||||
local INPUT_MARKER_VALUE = 2^INPUT_MARKER
|
||||
|
||||
errorlog:Show(true)
|
||||
errorlog:SetFont(ide.ofont)
|
||||
errorlog:StyleSetFont(wxstc.wxSTC_STYLE_DEFAULT, ide.ofont)
|
||||
errorlog:SetFont(ide.font.oNormal)
|
||||
errorlog:StyleSetFont(wxstc.wxSTC_STYLE_DEFAULT, ide.font.oNormal)
|
||||
errorlog:StyleClearAll()
|
||||
errorlog:SetMarginWidth(1, 16) -- marker margin
|
||||
errorlog:SetMarginType(1, wxstc.wxSTC_MARGIN_SYMBOL);
|
||||
@@ -22,13 +22,12 @@ errorlog:MarkerDefine(CURRENT_LINE_MARKER, wxstc.wxSTC_MARK_ARROWS, wx.wxBLACK,
|
||||
errorlog:MarkerDefine(INPUT_MARKER, wxstc.wxSTC_MARK_CHARACTER+string.byte('>'),
|
||||
wx.wxColour(127, 127, 127), wx.wxColour(240, 240, 240))
|
||||
errorlog:SetReadOnly(true)
|
||||
StylesApplyToEditor(ide.config.stylesoutshell,errorlog,ide.ofont,ide.ofontItalic)
|
||||
StylesApplyToEditor(ide.config.stylesoutshell,errorlog,ide.font.oNormal,ide.font.oItalic)
|
||||
|
||||
function ClearOutput()
|
||||
local current = errorlog:GetReadOnly()
|
||||
errorlog:SetReadOnly(false)
|
||||
errorlog:ClearAll()
|
||||
errorlog:SetReadOnly(current)
|
||||
errorlog:SetReadOnly(true)
|
||||
end
|
||||
|
||||
function DisplayOutputNoMarker(...)
|
||||
@@ -80,21 +79,29 @@ end
|
||||
-- logic to "unhide" wxwidget window using winapi
|
||||
pcall(function () return require 'winapi' end)
|
||||
local pid = nil
|
||||
local function unHideWxWindow(pidAssign)
|
||||
local function unHideWindow(pidAssign)
|
||||
-- skip if not configured to do anything
|
||||
if not ide.config.unhidewxwindow then return end
|
||||
if not ide.config.unhidewindow then return end
|
||||
if pidAssign then
|
||||
pid = pidAssign > 0 and pidAssign or nil
|
||||
end
|
||||
if pid and winapi then
|
||||
local win = winapi.find_window_ex(function(w)
|
||||
local wins = winapi.find_all_windows(function(w)
|
||||
return w:get_process():get_pid() == pid
|
||||
and w:get_class_name() == 'wxWindowClassNR'
|
||||
and ide.config.unhidewindow[w:get_class_name()]
|
||||
end)
|
||||
if win and not win:is_visible() then
|
||||
win:show()
|
||||
notebook:SetFocus() -- set focus back to the IDE window
|
||||
pid = nil
|
||||
for _,win in pairs(wins) do
|
||||
-- win:get_class_name() can return nil if the window is already gone
|
||||
-- between getting the list and this check
|
||||
local show = (ide.config.unhidewindow[win:get_class_name()] or 0) > 0
|
||||
if show and not win:is_visible()
|
||||
or not show and win:is_visible() then
|
||||
-- use show_async call (ShowWindowAsync) to avoid blocking the IDE
|
||||
-- if the app is busy or is being debugged
|
||||
win:show_async(show and winapi.SW_SHOW or winapi.SW_HIDE)
|
||||
notebook:SetFocus() -- set focus back to the IDE window
|
||||
pid = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -110,10 +117,9 @@ function CommandLineRun(cmd,wdir,tooutput,nohide,stringcallback,uid,endcallback)
|
||||
-- try to extract the name of the executable from the command
|
||||
-- the executable may not have the extension and may be in quotes
|
||||
local exename = string.gsub(cmd, "\\", "/")
|
||||
local _,_,fullname = string.find(exename,'^[\'"]([^\'"]-)[\'"]')
|
||||
exename = string.match(fullname or exename,'/?([^/]+)%s')
|
||||
or string.match(fullname or exename,'/?([^/]+)$')
|
||||
or fullname or exename
|
||||
local _,_,fullname = string.find(exename,'^[\'"]([^\'"]+)[\'"]')
|
||||
exename = fullname and string.match(fullname,'/?([^/]+)$')
|
||||
or string.match(exename,'/?([^/]-)%s') or exename
|
||||
|
||||
uid = uid or exename
|
||||
|
||||
@@ -125,15 +131,8 @@ function CommandLineRun(cmd,wdir,tooutput,nohide,stringcallback,uid,endcallback)
|
||||
|
||||
DisplayOutput(("Program starting as '%s'.\n"):format(cmd))
|
||||
|
||||
local proc = nil
|
||||
local customproc
|
||||
|
||||
if (tooutput) then
|
||||
customproc = wx.wxProcess(errorlog)
|
||||
customproc:Redirect()
|
||||
|
||||
proc = customproc
|
||||
end
|
||||
local proc = wx.wxProcess(errorlog)
|
||||
if (tooutput) then proc:Redirect() end -- redirect the output if requested
|
||||
|
||||
-- manipulate working directory
|
||||
local oldcwd
|
||||
@@ -156,13 +155,12 @@ function CommandLineRun(cmd,wdir,tooutput,nohide,stringcallback,uid,endcallback)
|
||||
-- a new process, but connected to the running one (e.g. DDE under Windows).
|
||||
if not pid or pid == -1 or pid == 0 then
|
||||
DisplayOutput(("Program unable to run as '%s'\n"):format(cmd))
|
||||
customproc = nil
|
||||
return
|
||||
end
|
||||
|
||||
DisplayOutput(("Program '%s' started in '%s' (pid: %d).\n")
|
||||
:format(uid, (wdir and wdir or wx.wxFileName.GetCwd()), pid))
|
||||
customprocs[pid] = {proc=customproc, uid=uid, endcallback=endcallback, started = os.clock()}
|
||||
customprocs[pid] = {proc=proc, uid=uid, endcallback=endcallback, started = TimeGet()}
|
||||
|
||||
local streamin = proc and proc:GetInputStream()
|
||||
local streamerr = proc and proc:GetErrorStream()
|
||||
@@ -177,7 +175,7 @@ function CommandLineRun(cmd,wdir,tooutput,nohide,stringcallback,uid,endcallback)
|
||||
streamouts[pid] = {stream=streamout, callback=stringcallback, out=true}
|
||||
end
|
||||
|
||||
unHideWxWindow(pid)
|
||||
unHideWindow(pid)
|
||||
nameTab(errorlog, "Output (running)")
|
||||
|
||||
return pid
|
||||
@@ -217,7 +215,6 @@ local function getStreams()
|
||||
(getInputLine() > -1 or errorlog:GetReadOnly()) then
|
||||
ActivateOutput()
|
||||
updateInputMarker()
|
||||
errorlog:SetFocus()
|
||||
end
|
||||
pfn = pfn and pfn()
|
||||
end
|
||||
@@ -251,10 +248,12 @@ errorlog:Connect(wx.wxEVT_END_PROCESS, function(event)
|
||||
-- delete markers and set focus to the editor if there is an input marker
|
||||
if errorlog:MarkerPrevious(errorlog:GetLineCount(), INPUT_MARKER_VALUE) > -1 then
|
||||
errorlog:MarkerDeleteAll(INPUT_MARKER)
|
||||
GetEditor():SetFocus()
|
||||
local editor = GetEditor()
|
||||
-- check if editor still exists; it may not if the window is closed
|
||||
if editor then editor:SetFocus() end
|
||||
end
|
||||
nameTab(errorlog, "Output")
|
||||
local runtime = os.clock() - customprocs[pid].started
|
||||
local runtime = TimeGet() - customprocs[pid].started
|
||||
|
||||
streamins[pid] = nil
|
||||
streamerrs[pid] = nil
|
||||
@@ -263,7 +262,7 @@ errorlog:Connect(wx.wxEVT_END_PROCESS, function(event)
|
||||
customprocs[pid].endcallback()
|
||||
end
|
||||
customprocs[pid] = nil
|
||||
unHideWxWindow(0)
|
||||
unHideWindow(0)
|
||||
DebuggerStop()
|
||||
DisplayOutput(("Program completed in %.2f seconds (pid: %d).\n")
|
||||
:format(runtime, pid))
|
||||
@@ -272,18 +271,18 @@ errorlog:Connect(wx.wxEVT_END_PROCESS, function(event)
|
||||
|
||||
errorlog:Connect(wx.wxEVT_IDLE, function()
|
||||
if (#streamins or #streamerrs) then getStreams() end
|
||||
unHideWxWindow()
|
||||
unHideWindow()
|
||||
end)
|
||||
|
||||
local jumptopatterns = {
|
||||
-- <filename>(line,linepos):
|
||||
"%s*([%w:/%\\_%-%.]+)%((%d+),(%d+)%)%s*:",
|
||||
"^%s*(.-)%((%d+),(%d+)%)%s*:",
|
||||
-- <filename>(line):
|
||||
"%s*([%w:/%\\_%-%.]+)%((%d+).*%)%s*:",
|
||||
-- <filename>:line:
|
||||
"%s*([%w:/%\\_%-%.]+):(%d+)%s*:",
|
||||
"^%s*(.-)%((%d+).*%)%s*:",
|
||||
--[string "<filename>"]:line:
|
||||
'.*%[string "([%w:/%\\_%-%.]+)"%]:(%d+)%s*:',
|
||||
'^.-%[string "([^"]+)"%]:(%d+)%s*:',
|
||||
-- <filename>:line:
|
||||
"^%s*(.-):(%d+)%s*:",
|
||||
}
|
||||
|
||||
errorlog:Connect(wxstc.wxEVT_STC_DOUBLECLICK,
|
||||
|
||||
@@ -233,7 +233,6 @@ end
|
||||
|
||||
-----------------------------------
|
||||
|
||||
|
||||
local function saveNotebook(nb)
|
||||
local cnt = nb:GetPageCount()
|
||||
|
||||
@@ -250,7 +249,6 @@ local function saveNotebook(nb)
|
||||
|
||||
for i=1,cnt do
|
||||
local id = nb:GetPageText(i-1)
|
||||
|
||||
local pg = nb:GetPage(i-1)
|
||||
local x,y = pg:GetPosition():GetXY()
|
||||
addTo(pagesX,x,id)
|
||||
@@ -303,14 +301,14 @@ local function loadNotebook(nb,str,fnIdConvert)
|
||||
if (not str) then return end
|
||||
local cnt = nb:GetPageCount()
|
||||
local sel = nb:GetSelection()
|
||||
|
||||
|
||||
-- store old pages
|
||||
local currentpages = {}
|
||||
for i=1,cnt do
|
||||
local id = nb:GetPageText(i-1)
|
||||
local newid = fnIdConvert and fnIdConvert(id) or id
|
||||
currentpages[newid] = {page = nb:GetPage(i-1), text = id, index = i-1}
|
||||
currentpages[newid] = currentpages[newid] or {}
|
||||
table.insert(currentpages[newid], {page = nb:GetPage(i-1), text = id, index = i-1})
|
||||
end
|
||||
|
||||
-- remove them
|
||||
@@ -318,7 +316,7 @@ local function loadNotebook(nb,str,fnIdConvert)
|
||||
nb:RemovePage(i-1)
|
||||
end
|
||||
|
||||
-- readd them and perform splits
|
||||
-- read them and perform splits
|
||||
local direction
|
||||
local splits = {
|
||||
X = wx.wxRIGHT,
|
||||
@@ -337,13 +335,13 @@ local function loadNotebook(nb,str,fnIdConvert)
|
||||
local instr = cmd:match("<(%w)>")
|
||||
if (not instr) then
|
||||
local id = fnIdConvert and fnIdConvert(cmd) or cmd
|
||||
local page = currentpages[id]
|
||||
if (page) then
|
||||
local pageind = next(currentpages[id] or {})
|
||||
if (pageind) then
|
||||
local page = currentpages[id][pageind]
|
||||
currentpages[id][pageind] = nil
|
||||
|
||||
nb:AddPage(page.page, page.text)
|
||||
currentpages[id] = nil
|
||||
if (direction) then
|
||||
nb:Split(t, direction)
|
||||
end
|
||||
if (direction) then nb:Split(t, direction) end
|
||||
finishPage(page)
|
||||
end
|
||||
end
|
||||
@@ -351,18 +349,18 @@ local function loadNotebook(nb,str,fnIdConvert)
|
||||
end
|
||||
|
||||
-- add anything we forgot
|
||||
for i,page in pairs(currentpages) do
|
||||
nb:AddPage(page.page, page.text)
|
||||
finishPage(page)
|
||||
for _,pagelist in pairs(currentpages) do
|
||||
for _,page in pairs(pagelist) do
|
||||
nb:AddPage(page.page, page.text)
|
||||
finishPage(page)
|
||||
end
|
||||
end
|
||||
|
||||
if (newsel) then
|
||||
nb:SetSelection(newsel)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
function SettingsRestoreView()
|
||||
local listname = "/view"
|
||||
local path = settings:GetPath()
|
||||
@@ -424,6 +422,7 @@ function SettingsRestoreEditorSettings()
|
||||
ide.config.interpreter = settingsReadSafe(settings,"interpreter",ide.config.interpreter)
|
||||
ProjectSetInterpreter(ide.config.interpreter)
|
||||
end
|
||||
|
||||
function SettingsSaveEditorSettings()
|
||||
local listname = "/editor"
|
||||
local path = settings:GetPath()
|
||||
|
||||
@@ -11,8 +11,8 @@ local out = bottomnotebook.shellbox
|
||||
local OUTPUT_MARKER = 3
|
||||
local remotesend
|
||||
|
||||
out:SetFont(ide.ofont)
|
||||
out:StyleSetFont(wxstc.wxSTC_STYLE_DEFAULT, ide.ofont)
|
||||
out:SetFont(ide.font.oNormal)
|
||||
out:StyleSetFont(wxstc.wxSTC_STYLE_DEFAULT, ide.font.oNormal)
|
||||
out:StyleClearAll()
|
||||
out:SetBufferedDraw(true)
|
||||
|
||||
@@ -32,7 +32,7 @@ out:MarkerDefine(BREAKPOINT_MARKER, wxstc.wxSTC_MARK_BACKGROUND, wx.wxBLACK, wx.
|
||||
out:MarkerDefine(OUTPUT_MARKER, wxstc.wxSTC_MARK_BACKGROUND, wx.wxBLACK, wx.wxColour(240, 240, 240))
|
||||
out:SetReadOnly(false)
|
||||
|
||||
SetupKeywords(out,"lua",nil,ide.config.stylesoutshell,ide.ofont,ide.ofontItalic)
|
||||
SetupKeywords(out,"lua",nil,ide.config.stylesoutshell,ide.font.oNormal,ide.font.oItalic)
|
||||
|
||||
local function getPromptLine()
|
||||
local totalLines = out:GetLineCount()
|
||||
@@ -254,6 +254,7 @@ local function executeShellCode(tx)
|
||||
fn, err = loadstring("return "..tx)
|
||||
if not forceexpression and err and
|
||||
(err:find("'<eof>' expected near '") or
|
||||
err:find("'%(' expected near") or
|
||||
err:find("unexpected symbol near '")) then
|
||||
fn, err = loadstring(tx)
|
||||
addedret = false
|
||||
@@ -284,7 +285,10 @@ local function executeShellCode(tx)
|
||||
if addedret then
|
||||
local mobdebug = require "mobdebug"
|
||||
for i,v in pairs(res) do -- stringify each of the returned values
|
||||
res[i] = mobdebug.line(v, {nocode = true, comment = 1})
|
||||
res[i] = (forceexpression and i > 1 and '\n' or '') ..
|
||||
mobdebug.line(v, {nocode = true, comment = 1,
|
||||
-- if '=' is used, then use multi-line serialized output
|
||||
indent = forceexpression and ' ' or nil})
|
||||
end
|
||||
-- add nil only if we are forced (using =) or if this is not a statement
|
||||
-- this is needed to print 'nil' when asked for 'foo',
|
||||
@@ -327,7 +331,7 @@ end
|
||||
local function displayShellIntro()
|
||||
DisplayShellDirect([[Welcome to the interactive Lua interpreter.
|
||||
Enter Lua code and press Enter to run it. Use Shift-Enter for multiline code.
|
||||
Use 'clear' to clear the shell output and the history. Prepend '=' to show values.]])
|
||||
Use 'clear' to clear the shell output and the history. Prepend '=' to show complex values on multiple lines.]])
|
||||
DisplayShellPrompt('')
|
||||
end
|
||||
|
||||
|
||||
@@ -224,9 +224,9 @@ function ReApplySpecAndStyles()
|
||||
local errorlog = ide.frame.bottomnotebook.errorlog
|
||||
local shellbox = ide.frame.bottomnotebook.shellbox
|
||||
|
||||
SetupKeywords(shellbox,"lua",nil,ide.config.stylesoutshell,ide.ofont,ide.ofontItalic)
|
||||
SetupKeywords(shellbox,"lua",nil,ide.config.stylesoutshell,ide.font.oNormal,ide.font.oItalic)
|
||||
|
||||
StylesApplyToEditor(ide.config.stylesoutshell,errorlog,ide.ofont,ide.ofontItalic)
|
||||
StylesApplyToEditor(ide.config.stylesoutshell,errorlog,ide.font.oNormal,ide.font.oItalic)
|
||||
end
|
||||
|
||||
function LoadConfigStyle()
|
||||
@@ -234,7 +234,7 @@ function LoadConfigStyle()
|
||||
"/cfg",
|
||||
"",
|
||||
"Lua file (*.lua)|*.lua|All files (*)|*",
|
||||
wx.wxOPEN + wx.wxFILE_MUST_EXIST)
|
||||
wx.wxFD_OPEN + wx.wxFD_FILE_MUST_EXIST)
|
||||
if fileDialog:ShowModal() == wx.wxID_OK then
|
||||
local cfg = {wxstc = wxstc, path = {}, editor = {}, view ={}, acandtip = {}, outputshell = {}, debugger={},}
|
||||
local cfgfn,err = loadfile(fileDialog:GetPath())
|
||||
|
||||
73
src/main.lua
73
src/main.lua
@@ -5,8 +5,8 @@
|
||||
-- that may have other versions present somewhere else in path/cpath
|
||||
local iswindows = os.getenv('WINDIR') or (os.getenv('OS') or ''):match('[Ww]indows')
|
||||
package.cpath = (iswindows
|
||||
and 'bin/?.dll;bin/clibs/?.dll;bin/clibs/?/?.dll;bin/clibs/?/?/?.dll;'
|
||||
or 'bin/?.so;bin/clibs/?.so;bin/clibs/?/?.so;bin/clibs/?/?/?.so;')
|
||||
and 'bin/?.dll;bin/clibs/?.dll;'
|
||||
or 'bin/clibs/?.dylib;bin/lib?.dylib;bin/?.so;bin/clibs/?.so;')
|
||||
.. package.cpath
|
||||
package.path = 'lualibs/?.lua;lualibs/?/?.lua;lualibs/?/init.lua;lualibs/?/?/?.lua;lualibs/?/?/init.lua;'
|
||||
.. package.path
|
||||
@@ -36,7 +36,12 @@ ide = {
|
||||
debugger = {
|
||||
verbose = false,
|
||||
},
|
||||
default = {
|
||||
name = 'untitled',
|
||||
fullname = 'untitled.lua',
|
||||
},
|
||||
outputshell = {},
|
||||
filetree = {},
|
||||
|
||||
styles = StylesGetDefault(),
|
||||
stylesoutshell = StylesGetDefault(),
|
||||
@@ -50,7 +55,7 @@ ide = {
|
||||
},
|
||||
|
||||
activateoutput = false, -- activate output/console on Run/Debug/Compile
|
||||
unhidewxwindow = false, -- try to unhide a wx window
|
||||
unhidewindow = false, -- to unhide a gui window
|
||||
allowinteractivescript = false, -- allow interaction in the output window
|
||||
filehistorylength = 20,
|
||||
projecthistorylength = 15,
|
||||
@@ -91,12 +96,32 @@ ide = {
|
||||
-- modTime = wxDateTime of disk file or nil,
|
||||
-- isModified = bool is the document modified? }
|
||||
ignoredFilesList = {},
|
||||
font = nil,
|
||||
fontItalic = nil,
|
||||
ofont = nil,
|
||||
ofontItalic = nil,
|
||||
font = {
|
||||
eNormal = nil,
|
||||
eItalic = nil,
|
||||
oNormal = nil,
|
||||
oItalic = nil,
|
||||
fNormal = nil,
|
||||
}
|
||||
}
|
||||
|
||||
function setLuaPaths(mainpath, os)
|
||||
-- (luaconf.h) in Windows, any exclamation mark ('!') in the path is replaced
|
||||
-- by the path of the directory of the executable file of the current process.
|
||||
-- this effectively prevents any path with an exclamation mark from working.
|
||||
-- if the path has an excamation mark, we allow Lua to expand it
|
||||
-- (for use in LUA_PATH/LUA_CPATH)
|
||||
if os == "Windows" and mainpath:find('%!') then mainpath = "!/../" end
|
||||
wx.wxSetEnv("LUA_PATH", package.path .. ';'
|
||||
.. mainpath.."lualibs/?/?.lua;"..mainpath.."lualibs/?.lua")
|
||||
|
||||
local clibs =
|
||||
os == "Windows" and mainpath.."bin/?.dll;"..mainpath.."bin/clibs/?.dll" or
|
||||
os == "Macintosh" and mainpath.."bin/lib?.dylib;"..mainpath.."bin/clibs/?.dylib" or
|
||||
os == "Unix" and mainpath.."bin/?.so;"..mainpath.."bin/clibs/?.so" or nil
|
||||
if clibs then wx.wxSetEnv("LUA_CPATH", package.cpath .. ';' .. clibs) end
|
||||
end
|
||||
|
||||
---------------
|
||||
-- process args
|
||||
local filenames = {}
|
||||
@@ -106,15 +131,23 @@ do
|
||||
local fullPath = arg[1] -- first argument must be the application name
|
||||
assert(type(fullPath) == "string", "first argument must be application name")
|
||||
|
||||
if not wx.wxIsAbsolutePath(fullPath) then
|
||||
ide.arg = arg
|
||||
ide.osname = wx.wxPlatformInfo.Get():GetOperatingSystemFamilyName()
|
||||
|
||||
-- on Windows use GetExecutablePath, which is Unicode friendly,
|
||||
-- whereas wxGetCwd() is not (at least in wxlua 2.8.12.2).
|
||||
-- some wxlua version on windows report wx.dll instead of *.exe.
|
||||
local exepath = wx.wxStandardPaths.Get():GetExecutablePath()
|
||||
if ide.osname == "Windows" and exepath:find("%.exe$") then
|
||||
fullPath = exepath
|
||||
elseif not wx.wxIsAbsolutePath(fullPath) then
|
||||
fullPath = wx.wxGetCwd().."/"..fullPath
|
||||
if wx.__WXMSW__ then fullPath = wx.wxUnix2DosFilename(fullPath) end
|
||||
end
|
||||
|
||||
ide.arg = arg
|
||||
ide.editorFilename = fullPath
|
||||
ide.config.path.app = fullPath:match("([%w_-%.]+)$"):gsub("%.[^%.]*$","")
|
||||
assert(ide.config.path.app, "no application path defined")
|
||||
|
||||
for index = 2, #arg do
|
||||
if (arg[index] == "-cfg" and index+1 <= #arg) then
|
||||
local str = arg[index+1]
|
||||
@@ -128,6 +161,8 @@ do
|
||||
table.insert(filenames,arg[index])
|
||||
end
|
||||
end
|
||||
|
||||
setLuaPaths(GetPathWithSep(ide.editorFilename), ide.osname)
|
||||
end
|
||||
|
||||
-----------------------
|
||||
@@ -222,6 +257,7 @@ local function loadSpecs()
|
||||
spec.sep = spec.sep or ""
|
||||
spec.iscomment = {}
|
||||
spec.iskeyword0 = {}
|
||||
spec.isstring = {}
|
||||
if (spec.lexerstyleconvert) then
|
||||
if (spec.lexerstyleconvert.comment) then
|
||||
for i,s in pairs(spec.lexerstyleconvert.comment) do
|
||||
@@ -233,6 +269,11 @@ local function loadSpecs()
|
||||
spec.iskeyword0[s] = true
|
||||
end
|
||||
end
|
||||
if (spec.lexerstyleconvert.stringtxt) then
|
||||
for i,s in pairs(spec.lexerstyleconvert.stringtxt) do
|
||||
spec.isstring[s] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -253,6 +294,8 @@ if app.preinit then app.preinit() end
|
||||
|
||||
do
|
||||
addConfig("cfg/user.lua",false)
|
||||
local home = os.getenv("HOME")
|
||||
if home then addConfig(home .. "/.zbs/user.lua",false) end
|
||||
for i,v in ipairs(configs) do
|
||||
addConfig(v,true,true)
|
||||
end
|
||||
@@ -320,10 +363,12 @@ if app.postinit then app.postinit() end
|
||||
-- app-specific menus (Help/About), which are not recognized by MacOS
|
||||
-- as special items unless SetMenuBar is done after menus are populated.
|
||||
ide.frame:SetMenuBar(ide.frame.menuBar)
|
||||
if ide.osname == 'Macintosh' then -- force refresh to fix the filetree
|
||||
pcall(function() ide.frame:ShowFullScreen(true) ide.frame:ShowFullScreen(false) end)
|
||||
end
|
||||
ide.frame:Show(true)
|
||||
|
||||
-- Call wx.wxGetApp():MainLoop() last to start the wxWidgets event loop,
|
||||
-- otherwise the wxLua program will exit immediately.
|
||||
-- Does nothing if running from wxLua, wxLuaFreeze, or wxLuaEdit since the
|
||||
-- MainLoop is already running or will be started by the C++ program.
|
||||
-- call wx.wxGetApp():MainLoop() last to start the wxWidgets event loop,
|
||||
-- otherwise the program will exit immediately.
|
||||
-- Does nothing if the MainLoop is already running.
|
||||
wx.wxGetApp():MainLoop()
|
||||
|
||||
@@ -152,6 +152,7 @@ function GetFileNameExt(filePath)
|
||||
end
|
||||
|
||||
function GetPathWithSep(wxfn)
|
||||
if type(wxfn) == 'string' then wxfn = wx.wxFileName(wxfn) end
|
||||
return wxfn:GetPath(bit.bor(wx.wxPATH_GET_VOLUME, wx.wxPATH_GET_SEPARATOR))
|
||||
end
|
||||
|
||||
@@ -168,12 +169,46 @@ function FileSysGet(dir,spec)
|
||||
end
|
||||
local f = browse:FindFirst(dir,spec)
|
||||
while #f>0 do
|
||||
table.insert(content,f)
|
||||
table.insert(content,(f:gsub("^file:",""))) -- remove file: protocol (wx2.9+)
|
||||
f = browse:FindNext()
|
||||
end
|
||||
return content
|
||||
end
|
||||
|
||||
function GetFullPathIfExists(p, f)
|
||||
if not p or not f then return end
|
||||
local file = wx.wxFileName(f)
|
||||
-- Normalize call is needed to make the case of p = '/abc/def' and
|
||||
-- f = 'xyz/main.lua' work correctly. Normalize() returns true if done.
|
||||
return (file:Normalize(wx.wxPATH_NORM_ALL, p)
|
||||
and file:FileExists()
|
||||
and file:GetFullPath())
|
||||
end
|
||||
|
||||
function FileWrite(file,content)
|
||||
local log = wx.wxLogNull() -- disable error reporting; will report as needed
|
||||
local file = wx.wxFile(file, wx.wxFile.write)
|
||||
if not file:IsOpened() then return nil, wx.wxSysErrorMsg() end
|
||||
|
||||
file:Write(content, #content)
|
||||
file:Close()
|
||||
return true
|
||||
end
|
||||
|
||||
function FileRead(file)
|
||||
local log = wx.wxLogNull() -- disable error reporting; will report as needed
|
||||
local file = wx.wxFile(file, wx.wxFile.read)
|
||||
if not file:IsOpened() then return end
|
||||
|
||||
local _, content = file:Read(file:Length())
|
||||
file:Close()
|
||||
return content, wx.wxSysErrorMsg()
|
||||
end
|
||||
|
||||
function FileRename(file1, file2) return wx.wxRenameFile(file1, file2) end
|
||||
|
||||
TimeGet = pcall(require, "socket") and socket.gettime or os.clock
|
||||
|
||||
function pairsSorted(t, f)
|
||||
local a = {}
|
||||
for n in pairs(t) do table.insert(a, n) end
|
||||
|
||||
14
tools/cg.lua
14
tools/cg.lua
@@ -400,8 +400,10 @@ return cgbinpath and {
|
||||
local function evCompile(event)
|
||||
local filename,info = GetEditorFileAndCurInfo()
|
||||
local editor = GetEditor()
|
||||
local glsl = editor and editor.spec and editor.spec.apitype and editor.spec.apitype == "glsl"
|
||||
local entryname = (glsl and "main" or info.selword)
|
||||
|
||||
if (not (filename and info.selword and cgbinpath)) then
|
||||
if (not (filename and entryname and cgbinpath)) then
|
||||
DisplayOutput("Error: Cg Compile: Insufficient parameters (nofile / not selected entry function!\n")
|
||||
return
|
||||
end
|
||||
@@ -415,11 +417,9 @@ return cgbinpath and {
|
||||
local args = data.customarg and data.custom or ""
|
||||
args = args:len() > 0 and args or nil
|
||||
|
||||
local fullname = filename:GetFullPath()
|
||||
local glsl = editor and editor.spec and editor.spec.apitype and editor.spec.apitype == "glsl"
|
||||
|
||||
local outname = fullname.."."..info.selword.."^"
|
||||
outname = args and outname..args:gsub("%s+%-",";-")..";^" or outname
|
||||
local fullname = filename:GetFullPath()
|
||||
local outname = fullname.."."..entryname.."^"
|
||||
outname = args and outname..args:gsub("%s*[%-%/]",";-")..";^" or outname
|
||||
outname = outname..profile[domain]..profile.ext
|
||||
outname = '"'..outname..'"'
|
||||
|
||||
@@ -430,7 +430,7 @@ return cgbinpath and {
|
||||
cmdline = args and cmdline..args.." " or cmdline
|
||||
cmdline = cmdline..data.domaindefs[domain]
|
||||
cmdline = cmdline.."-o "..outname.." "
|
||||
cmdline = cmdline.."-entry "..info.selword
|
||||
cmdline = cmdline.."-entry "..entryname
|
||||
|
||||
cmdline = cgbinpath.."/cgc.exe"..cmdline
|
||||
|
||||
|
||||
@@ -1,5 +1,46 @@
|
||||
-- author: Christoph Kubisch
|
||||
---------------------------------------------------------
|
||||
local StripCommentsC = StripCommentsC
|
||||
if not StripCommentsC then
|
||||
StripCommentsC = function(tx)
|
||||
local out = ""
|
||||
local lastc = ""
|
||||
local skip
|
||||
local skipline
|
||||
local skipmulti
|
||||
local tx = string.gsub(tx, "\r\n", "\n")
|
||||
for c in tx:gmatch(".") do
|
||||
local oc = c
|
||||
local tu = lastc..c
|
||||
skip = c == '/'
|
||||
|
||||
if ( not (skipmulti or skipline)) then
|
||||
if (tu == "//") then
|
||||
skipline = true
|
||||
elseif (tu == "/*") then
|
||||
skipmulti = true
|
||||
c = ""
|
||||
elseif (lastc == '/') then
|
||||
oc = tu
|
||||
end
|
||||
elseif (skipmulti and tu == "*/") then
|
||||
skipmulti = false
|
||||
c = ""
|
||||
elseif (skipline and lastc == "\n") then
|
||||
out = out.."\n"
|
||||
skipline = false
|
||||
end
|
||||
|
||||
lastc = c
|
||||
if (not (skip or skipline or skipmulti)) then
|
||||
out = out..oc
|
||||
end
|
||||
end
|
||||
|
||||
return out..lastc
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
local function ffiToApi(ffidef)
|
||||
local str = ffidef
|
||||
@@ -250,8 +291,16 @@ local function exec(wxfname,projectdir)
|
||||
editor:SetText(tx)
|
||||
end
|
||||
|
||||
if (RELPATH) then
|
||||
ffitoapiExec = exec
|
||||
if (not ide) then
|
||||
ffitoapi = function(fname)
|
||||
local f = io.open(fname,"rb")
|
||||
local tx = f:read("*a")
|
||||
f:close()
|
||||
tx = ffiToApi(tx)
|
||||
local f = io.open(fname,"wb")
|
||||
f:write(tx)
|
||||
f:close()
|
||||
end
|
||||
end
|
||||
|
||||
return {
|
||||
|
||||
BIN
zbstudio.exe
BIN
zbstudio.exe
Binary file not shown.
@@ -1,49 +1,21 @@
|
||||
CHANGELOG.md
|
||||
LICENSE
|
||||
README.md
|
||||
api/lua/baselib.lua
|
||||
api/lua/love2d.lua
|
||||
api/readme.txt
|
||||
bin/clibs/lfs.dll
|
||||
bin/clibs/mojoshader.dll
|
||||
bin/clibs/mime/core.dll
|
||||
bin/clibs/ssl.dll
|
||||
bin/clibs/socket/core.dll
|
||||
bin/clibs/wx/wxlua_msw28_wxbindadv.dll
|
||||
bin/clibs/wx/wxlua_msw28_wxbindaui.dll
|
||||
bin/clibs/wx/wxlua_msw28_wxbindbase.dll
|
||||
bin/clibs/wx/wxlua_msw28_wxbindcore.dll
|
||||
bin/clibs/wx/wxlua_msw28_wxbindgl.dll
|
||||
bin/clibs/wx/wxlua_msw28_wxbindhtml.dll
|
||||
bin/clibs/wx/wxlua_msw28_wxbindmedia.dll
|
||||
bin/clibs/wx/wxlua_msw28_wxbindnet.dll
|
||||
bin/clibs/wx/wxlua_msw28_wxbindstc.dll
|
||||
bin/clibs/wx/wxlua_msw28_wxbindxml.dll
|
||||
bin/clibs/wx/wxlua_msw28_wxbindxrc.dll
|
||||
bin/clibs/wx/wxlua_msw28_wxlua.dll
|
||||
bin/clibs/wx/wxlua_msw28_wxluadebug.dll
|
||||
bin/clibs/wx/wxlua_msw28_wxluasocket.dll
|
||||
bin/clibs/zmq.dll
|
||||
bin/libzmq.dll
|
||||
bin/lua.exe
|
||||
bin/lua5.1.dll
|
||||
bin/lua51.dll
|
||||
bin/winapi.dll
|
||||
bin/wx.dll
|
||||
bin/wxbase28_net_vc_custom.dll
|
||||
bin/wxbase28_vc_custom.dll
|
||||
bin/wxbase28_xml_vc_custom.dll
|
||||
bin/wxmsw28_adv_vc_custom.dll
|
||||
bin/wxmsw28_aui_vc_custom.dll
|
||||
bin/wxmsw28_core_vc_custom.dll
|
||||
bin/wxmsw28_gl_vc_custom.dll
|
||||
bin/wxmsw28_html_vc_custom.dll
|
||||
bin/wxmsw28_media_vc_custom.dll
|
||||
bin/wxmsw28_qa_vc_custom.dll
|
||||
bin/wxmsw28_richtext_vc_custom.dll
|
||||
bin/wxmsw28_stc_vc_custom.dll
|
||||
bin/wxmsw28_xrc_vc_custom.dll
|
||||
cfg/user-sample.lua
|
||||
interpreters/love2d.lua
|
||||
interpreters/luadeb.lua
|
||||
interpreters/moai.lua
|
||||
lualibs/copas/copas.lua
|
||||
lualibs/coxpcall/coxpcall.lua
|
||||
lualibs/luainspect/ast.lua
|
||||
@@ -83,6 +55,7 @@ lualibs/socket/tp.lua
|
||||
lualibs/socket/url.lua
|
||||
lualibs/ssl.lua
|
||||
lualibs/ssl/https.lua
|
||||
lualibs/testwell.lua
|
||||
spec/lua.lua
|
||||
src/defs.lua
|
||||
src/editor/autocomplete.lua
|
||||
|
||||
@@ -27,7 +27,11 @@ local app = {
|
||||
wx.wxArtProvider.Push(artProvider)
|
||||
|
||||
ide.config.interpreter = "luadeb"
|
||||
ide.config.unhidewxwindow = true -- allow unhiding of wx windows
|
||||
ide.config.unhidewindow = { -- allow unhiding of GUI windows
|
||||
-- 1 - unhide if hidden, 0 - hide if shown
|
||||
wxWindowClassNR = 1, -- wxwindows applications
|
||||
GLUT = 1, -- opengl applications (for example, moai)
|
||||
}
|
||||
ide.config.allowinteractivescript = true -- allow interaction in the output window
|
||||
|
||||
-- this needs to be in pre-init to load the styles
|
||||
@@ -60,14 +64,20 @@ local app = {
|
||||
|
||||
menuBar:Check(ID_CLEAROUTPUT, true)
|
||||
|
||||
-- load welcome.lua from myprograms/ if exists
|
||||
local fn = wx.wxFileName("myprograms/welcome.lua")
|
||||
if fn:FileExists() and
|
||||
(not ide.config.path.projectdir
|
||||
or string.len(ide.config.path.projectdir) == 0) then
|
||||
fn:Normalize() -- make absolute path
|
||||
LoadFile(fn:GetFullPath(),nil,true)
|
||||
ProjectUpdateProjectDir(fn:GetPath(wx.wxPATH_GET_VOLUME))
|
||||
-- load myprograms/welcome.lua if exists and no projectdir
|
||||
local projectdir = ide.config.path.projectdir
|
||||
if (not projectdir or string.len(projectdir) == 0
|
||||
or not wx.wxFileName(projectdir):DirExists()) then
|
||||
local home = wx.wxGetHomeDir():gsub("[\\/]$","")
|
||||
for _,dir in pairs({home, home.."/Desktop", ""}) do
|
||||
local fn = wx.wxFileName("myprograms/welcome.lua")
|
||||
-- normalize to absolute path
|
||||
if fn:Normalize(wx.wxPATH_NORM_ALL, dir) and fn:FileExists() then
|
||||
LoadFile(fn:GetFullPath(),nil,true)
|
||||
ProjectUpdateProjectDir(fn:GetPath(wx.wxPATH_GET_VOLUME))
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
@@ -79,7 +89,6 @@ local app = {
|
||||
settingsapp = "ZeroBraneStudio",
|
||||
settingsvendor = "ZeroBraneLLC",
|
||||
},
|
||||
|
||||
}
|
||||
|
||||
return app
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
editor.fontname = "Courier New"
|
||||
editor.caretline = true
|
||||
editor.showfncall = true
|
||||
editor.autotabs = false
|
||||
editor.usetabs = false
|
||||
editor.tabwidth = 2
|
||||
editor.usewrap = true
|
||||
editor.calltipdelay = 500
|
||||
|
||||
local G = ... -- this now points to the global environment
|
||||
if G.ide.osname == 'Macintosh' then filetree.fontsize = 11 end
|
||||
|
||||
filehistorylength = 20
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ local function DisplayAbout(event)
|
||||
</body>
|
||||
</html>]]
|
||||
|
||||
local dlg = wx.wxDialog(frame, wx.wxID_ANY, "About ZeroBane Studio")
|
||||
local dlg = wx.wxDialog(frame, wx.wxID_ANY, "About ZeroBrane Studio")
|
||||
local html = wx.wxLuaHtmlWindow(dlg, wx.wxID_ANY,
|
||||
wx.wxDefaultPosition, wx.wxSize(440, 270),
|
||||
wx.wxHW_SCROLLBAR_NEVER)
|
||||
@@ -73,11 +73,10 @@ local function DisplayAbout(event)
|
||||
topsizer:Add(html, 1, wx.wxALL, 10)
|
||||
topsizer:Add(line, 0, wx.wxEXPAND + wx.wxLEFT + wx.wxRIGHT, 10)
|
||||
topsizer:Add(button, 0, wx.wxALL + wx.wxALIGN_RIGHT, 10)
|
||||
topsizer:Fit(dlg)
|
||||
|
||||
dlg:SetAutoLayout(true)
|
||||
dlg:SetSizer(topsizer)
|
||||
topsizer:Fit(dlg)
|
||||
|
||||
dlg:ShowModal()
|
||||
dlg:Destroy()
|
||||
end
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 674 B After Width: | Height: | Size: 1.3 KiB |
Reference in New Issue
Block a user