Compare commits

...

234 Commits
0.39 ... 0.50

Author SHA1 Message Date
Paul Kulchenko
d68e7ff7ce Updated CHANGELOG for 0.50. 2014-03-10 14:23:04 -07:00
Paul Kulchenko
c4c3e7e51e Added explicit focus for Find field in the find dialog on OSX. 2014-03-10 14:22:26 -07:00
Paul Kulchenko
2460a82153 Updated AddConfig/RemoveConfig to refresh styles after changes (ref #166). 2014-03-08 23:08:35 -08:00
Paul Kulchenko
23a8d495f5 Added version dependency check for loaded plugins. 2014-03-08 23:07:47 -08:00
Paul Kulchenko
2ccd542610 Fixed shortcut menu generator to display default shortcuts. 2014-03-08 10:54:25 -08:00
Paul Kulchenko
1c66dc733f Reduced the number of inactivity checks and timer calls (ref #204). 2014-03-07 15:26:47 -08:00
Paul Kulchenko
5934b9733d Disabled singleinstance check by default on OSX (ref #204).
The singleinstance check is handled by OSX itself. In those rare cases
when the check in the IDE needed, it can be enabled by setting
`singleinstance = true` in the config.
2014-03-07 15:24:20 -08:00
Paul Kulchenko
7ae28cc479 Fixed removing focus from editor when IDE loses focus on OSX (ref #204).
This helps with CPU utilization and canceling tooltips after switching
to other controls in the IDE and then switching to a different app.
2014-03-07 15:22:02 -08:00
Paul Kulchenko
add8342f67 Fixed hiding calltip and auto-complete when switching between tabs on OSX.
Added manual call for KILL_FOCUS, which doesn't seem to be called on OSX
because of this wxwidgets issue (http://trac.wxwidgets.org/ticket/14269).
2014-03-07 15:17:22 -08:00
Paul Kulchenko
b89bb73476 Updated Marmalade Quick API for v7.2. 2014-03-06 20:45:13 -08:00
Paul Kulchenko
a00fa953c2 Updated Corona API for v2014.2189. 2014-03-06 20:06:48 -08:00
Paul Kulchenko
1e623b1d65 Fixed handling of getenv returning general message (Mobdebug v0.5511).
Some environments return an error message ("getenv is not supported"),
which needs to be handled when a port number is expected.
2014-03-06 18:25:47 -08:00
Paul Kulchenko
c0ddad642f Fixed lunching zbstudio from folders with spaces; thanks to @Asmageddon. 2014-03-06 18:21:55 -08:00
Paul Kulchenko
4f1286612b Updated scheme picker to apply styles to all windows. 2014-03-06 18:14:03 -08:00
Paul Kulchenko
267e631933 Added auxwindow attribute to style auxiliary windows. 2014-03-05 23:47:45 -08:00
Paul Kulchenko
0da23d376d Changed the order of applying styles to apply the main style last. 2014-03-05 23:46:26 -08:00
Paul Kulchenko
bdbfd3d71a Removed calltipbg attribute as it's replaced by calltip.bg. 2014-03-05 23:44:27 -08:00
Paul Kulchenko
11edc26279 Fixed calltip attribute to use/enable proper style. 2014-03-05 23:41:11 -08:00
Paul Kulchenko
4171d1ce3b Updated LfW interpreter to use project directory as current one (fixes #276).
Added `lfw.chdirtofile` option to use the current file directory (not the
project directory) as the current one.
2014-03-04 21:20:56 -08:00
Paul Kulchenko
bc866f8375 Updated README. 2014-03-03 18:01:09 -08:00
Paul Kulchenko
42f0bae28f Added sha2 library to provide sha256 hashing. 2014-03-02 22:07:17 -08:00
Paul Kulchenko
d0c712950f Added package GetRootPath/GetPackagePath calls (ref #166). 2014-03-02 22:01:33 -08:00
Paul Kulchenko
228b724f5b Fixed visibility of wrapped lines in console when going through history. 2014-03-02 21:58:53 -08:00
Paul Kulchenko
5fac7e15a8 Added package FindMenuItem API call (ref #166). 2014-03-02 16:40:12 -08:00
Paul Kulchenko
1338204787 Added API call to analyze one file. 2014-03-01 23:22:43 -08:00
Paul Kulchenko
afcbcfb522 Fixed syntax issues in definitions of IDE tables. 2014-02-28 22:45:03 -08:00
Paul Kulchenko
64a24768cd Fixed an issue in metalua files when syntax error is reported. 2014-02-28 17:42:04 -08:00
Paul Kulchenko
39c4cd6800 Removed unused files from metalua. 2014-02-28 17:39:13 -08:00
Paul Kulchenko
c854c97c22 Fixed arrow key handling in Local console (fixes #279). 2014-02-27 10:24:38 -08:00
Paul Kulchenko
35a5313e77 Added restoring markers after external modification and file reload. 2014-02-26 15:53:27 -08:00
Christoph Kubisch
2525736bea updates to shader apis (bugfix in GLSL atomic description) 2014-02-25 16:30:02 +01:00
Paul Kulchenko
102d470380 Fixed removing temporary files in GSL-shell interpreter. 2014-02-23 23:51:09 -08:00
Paul Kulchenko
9ade820252 Fixed tooltip positioning for long messages. 2014-02-20 17:56:47 -08:00
Paul Kulchenko
c2d6e7bed8 Fixed current line in debugging after activation of files with wrapped lines. 2014-02-20 14:23:02 -08:00
Paul Kulchenko
8a51d2512e Fixed spurious ESC after activation on Windows when modifiers are pressed. 2014-02-19 14:21:46 -08:00
Paul Kulchenko
542de89d16 Fixed skipping empty lines in tooltip formatting. 2014-02-19 11:12:59 -08:00
Paul Kulchenko
6aafdf9a84 Updated comment markup separators to apply markup in fewer cases. 2014-02-18 20:57:50 -08:00
Paul Kulchenko
c9b82f55b6 Fixed comment markup at the end of a file. 2014-02-18 20:53:38 -08:00
Paul Kulchenko
0497ef686a Fixed formatting calculations for tooltip to better fill the window. 2014-02-18 15:52:23 -08:00
Paul Kulchenko
476df369ba Adjusted tooltip position and content to always fit on the screen. 2014-02-17 23:05:24 -08:00
Paul Kulchenko
5c14fc1025 Added displaying number of selected characters and instances (closes #274). 2014-02-17 22:01:07 -08:00
Paul Kulchenko
92da4732c7 Merge branch 'master' of https://github.com/Yonaba/ZeroBraneStudio 2014-02-15 10:08:43 -08:00
Yonaba
c9c01ec769 Updated French translation 2014-02-15 09:18:07 +00:00
Paul Kulchenko
ebb6a8525e Fixed stopping debugging when switching projects with the same interpreter. 2014-02-13 23:02:41 -08:00
Paul Kulchenko
4edbe7b491 Added using safe load for external data instead of loadstring. 2014-02-12 20:43:18 -08:00
Paul Kulchenko
a21c39e5c8 Fixed auto-complete for classes with more than two levels. 2014-02-11 22:36:59 -08:00
Paul Kulchenko
74a39850f2 Removed paragraph-to-newline conversion for API tooltips. 2014-02-10 21:21:56 -08:00
Paul Kulchenko
c821336adf Fixed removal of paragraph breaks in tooltips after interpreter switch. 2014-02-10 20:35:24 -08:00
Paul Kulchenko
e36e455e1b Merge branch 'master' of https://github.com/bartoleo/ZeroBraneStudio 2014-02-10 14:45:09 -08:00
Paul Kulchenko
7f675b34ad Fixed API reloading that caused removal of paragraph breaks in tooltips. 2014-02-10 14:25:18 -08:00
Paul Kulchenko
33ab4a1196 Disable debugging termination when stack trace received from remote process.
It's not always desired to kill the remote process, which this termination
leads to. For example, Corona SDK displays an error message in the
Simulator and terminating the debugging, kills the simulator, which makes
it difficult to see the error message.
2014-02-10 14:23:08 -08:00
riidom
6cc90c2bd3 Update de.lua 2014-02-10 20:39:54 +01:00
Paul Kulchenko
9ef4438b4f Updated Linux scripts to remove custom libpng/zlib as it's fixed in wxwidgets. 2014-02-08 12:12:14 -08:00
Paul Kulchenko
d19db6e50d Fixed translations for stock menu items on Ubuntu 13.10 (ref #70). 2014-02-08 11:51:51 -08:00
Paul Kulchenko
93cfc76d78 Updated check for editor state during Edit menu display (ref #70).
This is a fix for 7f00380f that didn't fully addressed the issue.
So far this issue has only been demonstrated on Ubuntu 13.10; earlier
versions of Ubuntu (12.04 and 10.04) or Win/OSX are not affected.
2014-02-07 12:26:02 -08:00
Paul Kulchenko
e3ab970d5a Updated Corona API auto-complete/description to match v2013.2100 (ref #73). 2014-02-05 21:00:51 -08:00
Paul Kulchenko
7f00380fe1 Added check for editor state during Edit menu display (ref #70).
This avoids a strange run-time error on Linux that appears to be caused
by UpdateUI checks in Edit menu for editor object that is out of use.
2014-02-05 15:34:18 -08:00
Paul Kulchenko
f95a48212e Upgraded Mobdebug (0.551) to fix serialization of table/array indexes. 2014-02-05 14:56:43 -08:00
Paul Kulchenko
033c781467 Fixed an issue with spec/tools/interpreters filters not working from config. 2014-02-03 16:40:07 -08:00
bartoleo
3be3f700f4 fix typo 2014-02-03 14:47:00 +01:00
bartoleo
109972a5e7 added italian translations 2014-02-03 14:44:58 +01:00
Paul Kulchenko
a7cb89eda1 Added Russian translation for new items in the main menu (ref #70). 2014-02-01 17:49:01 -08:00
Paul Kulchenko
7cbef66b7d Updated all language files with new messages (ref #70). 2014-02-01 17:48:51 -08:00
Paul Kulchenko
d15837a69e Updated messages for better translation (ref #70). 2014-02-01 17:36:39 -08:00
Paul Kulchenko
2690f3deea Fixed messages script to work with LuaJIT. 2014-02-01 17:21:14 -08:00
Paul Kulchenko
82517bc57e Fixed console output with multiple new lines at the end. 2014-02-01 17:19:13 -08:00
Paul Kulchenko
f74653aba3 Added package GetApp method (ref #166). 2014-02-01 17:18:23 -08:00
Paul Kulchenko
879ab8f506 Reverted 5268b5f as flat namespace created OSX issues (fix #270, fix #264).
This breaks lua-dist support for Lua 5.2 on OSX (ref #225),
which should be fixed with wxwidgets upgrade (ref #260).
2014-01-30 19:53:50 -08:00
Paul Kulchenko
9b899b14b4 Added package GetDebugger API call (ref #166). 2014-01-28 23:28:39 -08:00
Paul Kulchenko
bf1d5c617e Added setting project directory passed as a parameter (second instance). 2014-01-25 23:01:15 -08:00
Christoph Kubisch
728beae0b2 shader tools: allow relative directories for binaries 2014-01-25 19:45:20 +01:00
Christoph Kubisch
ebe433a65a shader specs: add isfncall definition to allow indication style 2014-01-25 19:41:31 +01:00
Paul Kulchenko
6d8c2650aa Added Shift+Zoom to zoom all editors (closes #269). 2014-01-24 16:13:20 -08:00
Paul Kulchenko
0f51d31daa Fixed an issue with isfncall spec property not being checked. 2014-01-24 13:09:01 -08:00
Paul Kulchenko
0288253929 Added alpha setting for sel/seladd/caretlinebg styles. 2014-01-23 19:47:14 -08:00
Paul Kulchenko
777690862d Added package GetToolBar API call (ref #166). 2014-01-22 15:25:02 -08:00
Paul Kulchenko
10828dce8b Added seladd setting for styling additional selections. 2014-01-22 15:24:36 -08:00
Paul Kulchenko
62df942569 Fixed function localization in menu handlers. 2014-01-21 13:39:57 -08:00
Paul Kulchenko
059e093cb3 Added Select and Find Next/Prev (closes #268). 2014-01-21 13:34:41 -08:00
Paul Kulchenko
736c30a6bc Added showing search dialog for Quick Find on first search (closes #265). 2014-01-20 15:12:58 -08:00
Paul Kulchenko
c60770b2f5 Fixed default selection for search in case of multiple selections. 2014-01-18 22:21:32 -08:00
Paul Kulchenko
fc4611e1fa Fixed dependency of lfs/git dlls on lualib.dll. 2014-01-17 13:36:33 -08:00
Paul Kulchenko
01c6eeb782 Added nomousezoom option for Console/Output windows (closes #266). 2014-01-16 19:07:26 -08:00
Paul Kulchenko
cfb0b2f6bb Fixed an issue with activating proper tab after dragging. 2014-01-14 21:04:25 -08:00
Paul Kulchenko
24fe65848b Updated love2d api with LineJoin and few other calls (ref #247). 2014-01-13 21:16:13 -08:00
Paul Kulchenko
5f2a6b1382 Fixed displaying local console output with invalid unicode characters. 2014-01-12 17:07:42 -08:00
Paul Kulchenko
9f7b6c47ab Fixed displaying script output with invalid unicode characters. 2014-01-12 16:55:57 -08:00
Paul Kulchenko
1511c4c820 Updated OSX build script for wxwidgets 3.x (ref #260).
Removed workaround for wxwidgets issue 15008 that has been fixed in the
trunk (http://trac.wxwidgets.org/ticket/15008).
2014-01-11 14:49:06 -08:00
Paul Kulchenko
7c33e7bf55 Added error reporting when debugger server fails to start (closes #263). 2014-01-09 13:13:16 -08:00
Christoph Kubisch
570743a3da bugfix in dx compiler tool 2014-01-08 16:58:45 +01:00
Christoph Kubisch
62833599f4 glsl: added imageSize to spec and api 2014-01-08 16:56:45 +01:00
Paul Kulchenko
36f11ee2bd Updated build script to compile wxwidgets 3.x on Windows (ref #260). 2014-01-06 22:51:51 -08:00
Paul Kulchenko
2580ce36a8 Fixed drawing artifacts on Windows when line wrapping disabled (fixes #250). 2014-01-05 15:57:30 -08:00
Paul Kulchenko
8a4c3693f2 Fixed setting bom value for a new editor (fixes #258). 2014-01-03 18:42:42 -08:00
Paul Kulchenko
d2cb1690cb Added support for command line parameters for GSL-shell (ref #251). 2014-01-03 17:21:25 -08:00
Paul Kulchenko
c7b03095c4 Resolved conflict for Opt+Left (ref #252 and #203). 2014-01-02 14:46:54 -08:00
Paul Kulchenko
92b02bbe0e Added support for editor shortcuts and included standard OSX ones (closes #252). 2014-01-01 21:24:46 -08:00
Paul Kulchenko
f8ab060457 Added auto-complete for metamethods (closes #256). 2013-12-31 15:00:36 -08:00
Paul Kulchenko
3fe98ed092 Fixed auto-complete for values returned by 'core' functions (ref #256). 2013-12-31 14:59:36 -08:00
Paul Kulchenko
87fa5d1302 Added Minimize shortcut on OSX (closes #254). 2013-12-30 16:14:34 -08:00
Paul Kulchenko
09b81d2796 Added handling of command line parameters for love2d (ref #251). 2013-12-29 20:57:04 -08:00
Paul Kulchenko
2d9683675b Added handling of command line parameters (closes #251). 2013-12-29 20:56:35 -08:00
Paul Kulchenko
d524f06429 Switched to using temp files instead of -e option for debugging (ref #251).
This helps with passing parameters to launched processes.
2013-12-29 20:54:40 -08:00
Paul Kulchenko
8dfb5db642 Added calling of end callback for detached processes.
Since processes are detached, their END_PROCESS event is not going
to be called, registered callbacks need to be called manually.
2013-12-29 19:01:21 -08:00
Paul Kulchenko
cfc00e6c6b Updated love2d api with some missing calls (ref #247). 2013-12-28 16:15:16 -08:00
Paul Kulchenko
17522a2b16 Added skipping compile check for non-lua files in scratchpad. 2013-12-28 12:54:34 -08:00
Christoph Kubisch
902f40202a luxinia2 define some global vars if debugger is present 2013-12-28 18:17:08 +01:00
crazybutcher
34d25acb74 luxinia2 support 32 and 64 bit runtime 2013-12-27 22:10:51 +01:00
Christoph Kubisch
b65757584b luxinia2: interpreter bugfix 2013-12-27 14:01:32 +01:00
Christoph Kubisch
518c2ca90a Merge branch 'master' of ssh://git.code.sf.net/p/estrelaeditor/code
Conflicts:
	interpreters/luxinia2.lua
2013-12-27 11:23:07 +01:00
Christoph Kubisch
005eb4b52c luxinia2: new setup, added support for debugging with main.lua and rudimentary scratchpad functionality 2013-12-27 11:12:53 +01:00
Paul Kulchenko
daa06ac8de Added handling of (optional) BOM in UTF-8 encoded files (closes #246). 2013-12-26 11:34:52 -08:00
Paul Kulchenko
fdd1a9acdb Removed jumping to the current line after compilation errors. 2013-12-25 21:20:11 -08:00
Paul Kulchenko
f42c69b158 Added hint about removing backslash for invalid escape sequences. 2013-12-25 21:18:42 -08:00
Christoph Kubisch
991edfdac3 updated luxinia2 interpreter to reflect new luxinia2 structure 2013-12-25 15:42:11 +01:00
Paul Kulchenko
64552d2733 Updated Love2d API for 0.9.0. (closes #247). 2013-12-24 17:33:13 -08:00
Christoph Kubisch
a7819bd022 Merge branch 'master' of ssh://git.code.sf.net/p/estrelaeditor/code 2013-12-23 21:06:56 +01:00
Christoph Kubisch
529e8b910f Merge remote-tracking branch 'zbstudio/master' 2013-12-23 21:05:42 +01:00
Christoph Kubisch
e886befe4c Merge remote-tracking branch 'zbstudio/master' 2013-12-22 18:08:34 +01:00
CrazyButcher
df1583b9c2 allow tool exe paths to be set in config prior load 2013-12-22 18:01:59 +01:00
Paul Kulchenko
a83f8bd5ac Updated CHANGELOG for 0.40. 2013-12-14 14:12:47 -08:00
Paul Kulchenko
92d08a0393 Updated Mobdebug (v0.55). 2013-12-14 14:10:54 -08:00
Paul Kulchenko
63eb7164b2 Added 'busted' interpreter. 2013-12-13 13:35:05 -08:00
Paul Kulchenko
23b37b397b Updated README. 2013-12-12 13:32:39 -08:00
Christoph Kubisch
cabc579b4b hlsl spec updated, glslc by default does some includes now 2013-12-11 13:02:12 +01:00
Paul Kulchenko
e08bb4f41d Updated samples with missing indicator constants (closes #243). 2013-12-10 15:22:23 -08:00
Paul Kulchenko
9e558fba3a Updated CHANGELOG with recent changes. 2013-12-06 22:09:02 -08:00
Paul Kulchenko
22cf8f86d6 Updated MANIFEST files for LuaDist changes (closes #225). 2013-12-04 14:18:23 -08:00
Paul Kulchenko
d1c49f065b Merge branch 'luadist-package' 2013-12-03 22:27:16 -08:00
Paul Kulchenko
5268b5fb0d Updated OSX executables and added 'fake' proxy for lua-dist support (ref #225).
LuaDist relies on using liblua.dylib for all its modules with the same
name for both Lua 5.1 and Lua 5.2 interpreters. This presents an issue for
ZBS as it needs not only to refer to a proper liblua.dylib, but also to
avoid loading two interpreters as its own interperter loads its own
library.

To resolve this, liblua.dylib doesn't export any symbols (it's a dummy
library), but it needs to be present to satisfy dyld dependency (as some
of the libraries and LuaDist build process are outside of our control).

All the other Lua symbols are already available in memory, but to make
LuaDist libraries to use them, we enforce flat namespace.
2013-12-03 15:28:40 -08:00
Paul Kulchenko
df6ac05478 Fixed values 'captured' by redirected 'print' and not collected (fixes #240). 2013-12-02 18:20:48 -08:00
Paul Kulchenko
a71cd3494b Added live coding support for GSL-shell (closes #239). 2013-12-01 18:32:19 -08:00
Paul Kulchenko
28f443f665 Disabled compilation check for scratchpad when skipcompile is set (ref #239). 2013-12-01 18:30:49 -08:00
Paul Kulchenko
1df2f42938 Updated handling of case-insensitive names during debugging on OSX (Mobdebug v0.545). 2013-11-29 16:56:30 -08:00
Paul Kulchenko
25d118c87d Updated package onEditorPreSave to be called on SaveAs events (ref #166). 2013-11-29 16:30:10 -08:00
Paul Kulchenko
18498e0aae Added support for product-specific links in the Help menu. 2013-11-29 11:06:03 -08:00
Paul Kulchenko
8819e337b8 Added 'edge' style to the color schemes (ref #237). 2013-11-27 14:50:55 -08:00
Paul Kulchenko
ef52c9d328 Added ability to set 'edge' style properties individually (ref #237). 2013-11-27 13:10:49 -08:00
Paul Kulchenko
e9d71b05b9 Fixed typo in fold style definition (ref #237). 2013-11-27 13:09:58 -08:00
Mike Richards
17fdbb3eda Add edge to styles 2013-11-27 13:54:30 -05:00
Mike Richards
133ebe2435 Add fold margin checker color to styles 2013-11-27 13:53:15 -05:00
Mike Richards
bf8450afe3 Add edge line and fold margin checker color 2013-11-27 13:47:37 -05:00
Paul Kulchenko
ec2775bb5a Fixed console output being limited in addition to stack result limit. 2013-11-22 11:32:32 -08:00
Christoph Kubisch
c82d9d4f1b prefer fx and fxh in hlsl over cg 2013-11-22 13:56:24 +01:00
Christoph Kubisch
3bb2926c88 dx tool: added support to compile effect file, binary outputs are "fxo" files 2013-11-22 13:49:00 +01:00
Paul Kulchenko
fe8b0eb7e8 Updated icon bundle to eliminate large icons.
The bundle file was generating "DIB Header: Image width > 32767 pixels for
file" errors in some (!) cases on Windows, which doesn't seem to happen
with the bundle that doesn't include 128x128 and 256x256 icons.
2013-11-20 16:33:53 -08:00
Christoph Kubisch
7958ebc2eb tidy up estrela tools a bit (remove key strokes from cgc, remove luxinia res viewer, rename perforce files to get loaded again) 2013-11-20 15:40:31 +01:00
Paul Kulchenko
9235722a76 Fixed hang in auto-complete on expressions involving '...' (fixes #235). 2013-11-19 23:15:14 -08:00
Paul Kulchenko
caa8241ca9 Fixed auto-complete for string values (broken by 933aacc2). 2013-11-19 23:11:14 -08:00
Paul Kulchenko
aeb266c95b Fixed using load.* commands in config files and reverted 4cb9ab/a8cfd2. 2013-11-19 16:44:57 -08:00
Christoph Kubisch
4cb9ab4662 bugfix in estrela.lua 2013-11-19 16:17:02 +01:00
Christoph Kubisch
8c3fde6755 changed glslc option to reflect new version 2013-11-19 16:05:53 +01:00
Christoph Kubisch
a8cfd219ce bugfix to estrela loading behavior (disabled by last zbstudio merge), please update user.lua with content from estrela.lua 2013-11-19 15:58:02 +01:00
Christoph Kubisch
f208454003 glsl additions 2013-11-19 15:56:58 +01:00
Paul Kulchenko
792f745832 Updated application icon to a bit brighter one on OSX (closes #196). 2013-11-17 21:05:20 -08:00
Paul Kulchenko
1106d861ba Removed some of the snippets as they are available as plugins. 2013-11-15 16:11:17 -08:00
Paul Kulchenko
355f72099e Updated build script on OSX to not require 10.6 SDK (closes #231). 2013-11-14 15:41:31 -08:00
Paul Kulchenko
292f7b176b Added changing directory when launching on Linux (closes #157). 2013-11-09 23:47:45 -08:00
Paul Kulchenko
be03488583 Fixed crash when LUA_DEV environmental variable is not set (fixes #228). 2013-11-08 17:23:05 -08:00
Paul Kulchenko
83a663c369 Added setting PATH for LfW to allow loading of DLL dependencies. 2013-11-03 23:13:32 -08:00
Paul Kulchenko
5afa0fe4e8 Added logic to set architecture dynamically for luadist (ref #225). 2013-10-31 11:56:04 -07:00
Paul Kulchenko
838eae88f4 Fixed cmake cache filename (ref #225). 2013-10-31 11:56:03 -07:00
Paul Kulchenko
b253853241 Added luadist bootstrap dependencies for Linux (ref #225). 2013-10-31 11:56:01 -07:00
Paul Kulchenko
d0584dd62f Fixed a luadist error thrown when retrieve_pkg_info fails (ref #225). 2013-10-31 11:56:00 -07:00
Paul Kulchenko
74b39853b2 Added option to load luadist as a module (ref #225). 2013-10-31 11:55:58 -07:00
Paul Kulchenko
6b0d279f37 Added luadist bootstrap dependencies for OSX (ref #225). 2013-10-31 11:55:57 -07:00
Paul Kulchenko
2a0ff7b7f8 Added proxy dll for Lua 5.2 (ref #225). 2013-10-31 11:55:56 -07:00
Paul Kulchenko
1f2ce466f5 Added luadist bootstrap dependencies for Windows (ref #225). 2013-10-31 11:55:54 -07:00
Paul Kulchenko
30dfe9e99b Added package GetInterpreters method (ref #166, #225). 2013-10-31 11:55:52 -07:00
Paul Kulchenko
3acb334623 Added package AddConsoleAlias/RemoveConsoleAlias methods (ref #166, #225). 2013-10-31 11:55:51 -07:00
Paul Kulchenko
27c0fb9c55 Disabled output activation for messages redirected to Console (ref #225). 2013-10-31 11:55:50 -07:00
Paul Kulchenko
96005b74d9 Updated instructions for building Lua 5.2 proxy dll. 2013-10-30 11:55:08 -07:00
Paul Kulchenko
8489658f7d Fixed incorrect UTF-8 sequence in UTF-8 validity check. 2013-10-29 17:52:55 -07:00
Paul Kulchenko
9b0f9e52be Store os specific clibs path to make it available to plugins. 2013-10-25 18:01:15 -07:00
Paul Kulchenko
bdee0aea26 Added version property to the Lua interpreters. 2013-10-25 17:58:21 -07:00
Paul Kulchenko
7d2982fdbd Added instructions for building proxy dll for Lua 5.2. 2013-10-25 17:50:25 -07:00
Paul Kulchenko
f57d254136 Added new location for Marmalade Quick v7+ and s3e path logic (fixes #226). 2013-10-24 16:55:40 -07:00
Paul Kulchenko
fca8c25862 Fixed Un/Comment menu for Output/Console windows. 2013-10-24 15:29:54 -07:00
Paul Kulchenko
8a5e66cfae Added directory creation (if needed) to file saving. 2013-10-23 21:15:26 -07:00
Paul Kulchenko
1ff0955c52 Merge branch 'project-settings' 2013-10-23 11:21:21 -07:00
Paul Kulchenko
3f4b711efe Added support for symlinks in the filetree (with recursion protection). 2013-10-22 17:09:44 -07:00
Paul Kulchenko
e79016323d Added package AddConfig/RemoveConfig methods (ref #166). 2013-10-22 11:39:57 -07:00
Paul Kulchenko
50f4daf0d5 Added package GetProject method (ref #166). 2013-10-22 11:39:21 -07:00
Paul Kulchenko
2452f963b5 Added package onProjectPreLoad method (ref #166). 2013-10-22 11:38:06 -07:00
Paul Kulchenko
3c87a0a86a Moved restoring project before loading files (ref #107).
This is needed to take project configuration into account before files are
loaded.
2013-10-22 11:36:12 -07:00
Paul Kulchenko
d818952900 Reorganized loading configuration files (ref #107). 2013-10-22 11:27:37 -07:00
Paul Kulchenko
799ee9061c Fixed format of the file name reported after compilation errors. 2013-10-21 22:09:22 -07:00
Paul Kulchenko
ca32b04038 Fixed jumping to compilation error (if any) after Run/Debug. 2013-10-21 21:38:07 -07:00
Paul Kulchenko
948c841552 Added workaround for conflict with Scintilla shortcuts on Linux.
Details: http://wxwidgets.10942.n7.nabble.com/Menu-shortcuts-inconsistentcy-issue-td85065.html
2013-10-19 21:15:13 -07:00
Paul Kulchenko
f5ce0698de Disabled commenting for file types that don't specify line comments. 2013-10-19 21:14:01 -07:00
Paul Kulchenko
21f0fa18b4 Merge branch 'filetree-operations' 2013-10-19 15:59:25 -07:00
Paul Kulchenko
ac02eac58a Updated menu definitions for consistency. 2013-10-18 17:55:33 -07:00
Paul Kulchenko
8a11400718 Updated use of unpack for consistency and Lua 5.2 compatibility. 2013-10-17 19:55:47 -07:00
Paul Kulchenko
8d2ec214f0 Updated 'Open with Default Program' on Windows to work with spaces in names (#123). 2013-10-17 14:46:07 -07:00
Paul Kulchenko
68b5a625ec Updated cmake installation script to install to '/Applications' on OSX. 2013-10-17 11:42:36 -07:00
Paul Kulchenko
2f3de56dde Updated OSX build script to revert wxwidgets commit to fix auto-complete crash. 2013-10-17 11:21:26 -07:00
Paul Kulchenko
dec1e9a534 Fixed disabling 'Open with Default Program' on OSX (ref #123). 2013-10-16 22:59:21 -07:00
Paul Kulchenko
c462ebfbcf Fixed file tree update after changes on OSX (ref #123). 2013-10-16 22:15:04 -07:00
Paul Kulchenko
85f3e5fa9b Fixed copying full path on OSX (ref #123). 2013-10-16 22:07:10 -07:00
Paul Kulchenko
22d70d3e58 Fixed 'Open with Default Program' for paths with spaces on Windows (ref #123). 2013-10-16 22:05:44 -07:00
Paul Kulchenko
e1dc8b7085 Added 'Open with Default Program' to file tree operations (ref #123). 2013-10-16 19:40:45 -07:00
Paul Kulchenko
0387661c67 Added toggling directory on Enter (ref #123). 2013-10-16 17:34:51 -07:00
Paul Kulchenko
5269f769c4 Added 'Copy Full Path' to file tree operations (ref #123). 2013-10-16 17:34:50 -07:00
Paul Kulchenko
3e5fc7ddd0 Added deleting file/directory to file tree operations (ref #123). 2013-10-16 17:34:40 -07:00
Paul Kulchenko
e7415e30c6 Added processing of packages from $HOME/.zbstudio/packages folder (#166). 2013-10-16 16:27:33 -07:00
Paul Kulchenko
124b570ad4 Updated Start debugging hint to clarify. 2013-10-16 15:34:43 -07:00
Paul Kulchenko
eda840d02d Fixed folding issue (caused by math.mod not available in LuaJIT). 2013-10-16 15:05:07 -07:00
Paul Kulchenko
88612ba72e Added 'New File' and 'New Directory' to file operations (ref #123). 2013-10-16 13:35:15 -07:00
Paul Kulchenko
b9f82e6c38 Updated single-click toggle to allow rename/move directories (ref #123). 2013-10-16 10:30:26 -07:00
Paul Kulchenko
bf3320b100 Updated normalization flags as some path parts were changed to dots. 2013-10-16 10:24:10 -07:00
Paul Kulchenko
e95749e9f8 Added error reporting for failed rename operations (ref #123). 2013-10-15 11:31:54 -07:00
Paul Kulchenko
913244102a Added re-opening editor tabs affected by directory move/rename (ref #123). 2013-10-15 11:02:23 -07:00
Paul Kulchenko
edc06b2a84 Added package FindDocumentsByPartialPath method (ref #166). 2013-10-15 10:39:11 -07:00
Paul Kulchenko
a15dd00a33 Added existing file overwrite confirmation when renaming (ref #123). 2013-10-15 09:40:15 -07:00
Paul Kulchenko
cde478baaf Added existing file overwrite confirmation when saving. 2013-10-15 09:39:50 -07:00
Paul Kulchenko
37a117a7c0 Removed 'file no longer exists' message after moving opened files (ref #123). 2013-10-15 09:11:22 -07:00
Paul Kulchenko
04e10efdc8 Added creating intermediate directories during file rename (ref #123). 2013-10-14 21:31:19 -07:00
Paul Kulchenko
5c94f7b775 Added in-place editing of file and folder names (ref #123). 2013-10-14 21:04:49 -07:00
Paul Kulchenko
8e64765f42 Updated editor tab processing using FindDocument method. 2013-10-14 17:04:13 -07:00
Paul Kulchenko
abc5ee0ebe Added refreshing editor tab after drag-n-drop operation (ref #123). 2013-10-14 17:03:23 -07:00
Paul Kulchenko
5c564a2d6e Added drag-n-drop operation to move files in the project tree (ref #123). 2013-10-13 22:50:42 -07:00
Paul Kulchenko
f539047802 Updated shortcut for Replace All to avoid conflict on OSX (fixes #220). 2013-10-13 20:53:56 -07:00
Paul Kulchenko
58b6c80dcb Added package AddMarker/RemoveMarker methods (ref #166). 2013-10-13 16:02:51 -07:00
Paul Kulchenko
4bce9e9b92 Added package GetStatusBar method (ref #166). 2013-10-13 16:02:50 -07:00
Paul Kulchenko
f4a48f5add Fixed debugger marker calculations to avoid marker conflicts. 2013-10-13 16:02:35 -07:00
Paul Kulchenko
230efa465c Fixed color references in marker config examples. 2013-10-12 23:03:31 -07:00
Paul Kulchenko
a6cd382a0f Fixed Step Over/Out to stay in the same coroutine; Mobdebug 0.543 (closes #217). 2013-10-12 10:59:38 -07:00
Paul Kulchenko
783eaf4241 Fixed case sensitivity in matching of file name in error messages (fixes #216). 2013-10-11 17:30:37 -07:00
Paul Kulchenko
3096b4dfc0 Fixed tab text after SaveAs and loading files into the same tab. 2013-10-11 17:30:26 -07:00
Paul Kulchenko
a4dad82b02 Updated MANIFEST to include all packages. 2013-10-10 11:34:52 -07:00
Paul Kulchenko
7e2ebfe88c Updated SetDocumentModified to use current tab text. 2013-10-08 14:15:15 -07:00
Paul Kulchenko
1d72d7670a Added package GetDocuments and document methods (ref #166). 2013-10-08 14:15:14 -07:00
Paul Kulchenko
c33bd66fe7 Added EscapeMagic function to escape magic characters. 2013-10-08 14:15:12 -07:00
Paul Kulchenko
49d7711b9b Added SciTeLuaIDE color scheme (thanks to Jayanth Acharya). 2013-10-08 11:52:49 -07:00
119 changed files with 14116 additions and 6127 deletions

View File

@@ -1,5 +1,255 @@
# ZeroBrane Studio Changelog
## v0.50 (Mar 10 2014)
### Highlights
- Fixed opening files and launching on OSX 10.6.x and 10.9.1+.
- Improved CPU utilization when idle on OSX.
- Added handling of command-line parameters.
- Implemented various auto-complete and tooltip improvements.
- Updated Love2d API for 0.9.0.
- Updated Corona API auto-complete/description to match v2014.2189 (G2.0).
- Updated Marmalade Quick API for v7.2.
- Updated French, German, Italian, and Russian translations.
### Special thanks
- To [Asmageddon](https://github.com/Asmageddon) for fixed launching zbstudio from folders with spaces.
- To [Christoph Kubisch](https://github.com/pixeljetstream) for various luxinia2 fixes.
- To [Yonaba](https://github.com/Yonaba/) for updated French translation.
- To [riidom](https://github.com/riidom/) for updated German translation.
- To [bartoleo](https://github.com/bartoleo/) for updated Italian translations.
### Improvements
- Added explicit focus for Find field in the find dialog on OSX.
- Added version dependency check for loaded plugins.
- Added `auxwindow` attribute to style auxiliary windows.
- Added sha2 library to provide sha256 hashing.
- Added package GetRootPath/GetPackagePath calls (ref #166).
- Added package FindMenuItem API call (ref #166).
- Added API call to analyze one file.
- Added restoring markers after external modification and file reload.
- Added displaying number of selected characters and instances (closes #274).
- Added using safe load for external data instead of loadstring.
- Added check for editor state during Edit menu display (ref #70).
- added italian translations; thanks to [bartoleo](https://github.com/bartoleo/).
- Added Russian translation for new items in the main menu (ref #70).
- Added package GetApp method (ref #166).
- Added package GetDebugger API call (ref #166).
- Added setting project directory passed as a parameter (second instance).
- Added Shift+Zoom to zoom all editors (closes #269).
- Added `alpha` setting for sel/seladd/caretlinebg styles.
- Added package GetToolBar API call (ref #166).
- Added `seladd` setting for styling additional selections.
- Added `Select and Find Next/Prev` (closes #268).
- Added showing search dialog for Quick Find on first search (closes #265).
- Added `nomousezoom` option for Console/Output windows (closes #266).
- Added error reporting when debugger server fails to start (closes #263).
- Added support for command line parameters for GSL-shell (ref #251).
- Added support for editor shortcuts and included standard OSX ones (closes #252).
- Added auto-complete for metamethods (closes #256).
- Added Minimize shortcut on OSX (closes #254).
- Added handling of command line parameters for love2d (ref #251).
- Added handling of command line parameters (closes #251).
- Added calling of end callback for detached processes.
- Added skipping compile check for non-lua files in scratchpad.
- Added handling of (optional) BOM in UTF-8 encoded files (closes #246).
- Added hint about removing backslash for invalid escape sequences.
- Adjusted tooltip position and content to always fit on the screen.
- allow tool exe paths to be set in config prior load
- Changed the order of applying styles to apply the main style last.
- Disabled singleinstance check by default on OSX (ref #204).
- Disable debugging termination when stack trace received from remote process.
- glsl: added imageSize to spec and api
- luxinia2 define some global vars if debugger is present
- luxinia2 support 32 and 64 bit runtime
- luxinia2: new setup, added support for debugging with main.lua and rudimentary scratchpad functionality
- Reduced the number of inactivity checks and timer calls (ref #204).
- Removed `calltipbg` attribute as it's replaced by `calltip.bg`.
- Removed unused files from metalua.
- Removed paragraph-to-newline conversion for API tooltips.
- Resolved conflict for Opt+Left (ref #252 and #203).
- Removed jumping to the current line after compilation errors.
- Switched to using temp files instead of -e option for debugging (ref #251).
- shader tools: allow relative directories for binaries
- shader specs: add isfncall definition to allow indication style
- Updated AddConfig/RemoveConfig to refresh styles after changes (ref #166).
- Updated Marmalade Quick API for v7.2.
- Updated Corona API for v2014.2189.
- Updated scheme picker to apply styles to all windows.
- Updated LfW interpreter to use project directory as current one (fixes #276).
- Updated README.
- Updated comment markup separators to apply markup in fewer cases.
- Updated French translation; thanks to [Yonaba](https://github.com/Yonaba/).
- Update de.lua; thanks to [riidom](https://github.com/riidom/).
- Updated Linux scripts to remove custom libpng/zlib as it's fixed in wxwidgets.
- Updated check for editor state during Edit menu display (ref #70).
- Updated Corona API auto-complete/description to match v2013.2100 (ref #73).
- Updated all language files with new messages (ref #70).
- Updated messages for better translation (ref #70).
- Updated love2d api with LineJoin and few other calls (ref #247).
- Updated OSX build script for wxwidgets 3.x (ref #260).
- Updated build script to compile wxwidgets 3.x on Windows (ref #260).
- Updated love2d api with some missing calls (ref #247).
- updated luxinia2 interpreter to reflect new luxinia2 structure
- Updated Love2d API for 0.9.0. (closes #247).
- Upgraded Mobdebug (0.551) to fix serialization of table/array indexes.
- updates to shader apis (bugfix in GLSL atomic description)
### Incompatibilities
- Updated LfW interpreter to use project directory as current one (fixes #276).
- Removed `styles.calltipbg` as it is replaced by `styles.calltip.bg`.
### Fixes
- Fixed shortcut menu generator to display default shortcuts.
- Fixed removing focus from editor when IDE loses focus on OSX (ref #204).
- Fixed hiding calltip and auto-complete when switching between tabs on OSX.
- Fixed handling of getenv returning general message (Mobdebug v0.5511).
- Fixed launching zbstudio from folders with spaces; thanks to @Asmageddon.
- Fixed `calltip` attribute to use/enable proper style.
- Fixed visibility of wrapped lines in console when going through history.
- Fixed syntax issues in definitions of IDE tables.
- Fixed an issue in metalua files when syntax error is reported.
- Fixed arrow key handling in Local console (fixes #279).
- Fixed removing temporary files in GSL-shell interpreter.
- Fixed tooltip positioning for long messages.
- Fixed current line in debugging after activation of files with wrapped lines.
- Fixed spurious ESC after activation on Windows when modifiers are pressed.
- Fixed skipping empty lines in tooltip formatting.
- Fixed comment markup at the end of a file.
- Fixed formatting calculations for tooltip to better fill the window.
- Fixed stopping debugging when switching projects with the same interpreter.
- Fixed auto-complete for classes with more than two levels.
- Fixed removal of paragraph breaks in tooltips after interpreter switch.
- Fixed API reloading that caused removal of paragraph breaks in tooltips.
- Fixed translations for stock menu items on Ubuntu 13.10 (ref #70).
- Fixed an issue with spec/tools/interpreters filters not working from config.
- Fixed messages script to work with LuaJIT.
- Fixed console output with multiple new lines at the end.
- Fixed issues on OSX 10.6.x and 10.9.1+ caused by flat namespace (fix #270, fix #264).
- Fixed an issue with `isfncall` spec property not being checked.
- Fixed function localization in menu handlers.
- Fixed default selection for search in case of multiple selections.
- Fixed dependency of lfs/git dlls on lualib.dll.
- Fixed an issue with activating proper tab after dragging.
- Fixed displaying local console output with invalid unicode characters.
- Fixed displaying script output with invalid unicode characters.
- Fixed drawing artifacts on Windows when line wrapping disabled (fixes #250).
- Fixed setting bom value for a new editor (fixes #258).
- Fixed auto-complete for values returned by 'core' functions (ref #256).
## v0.40 (Dec 14 2013)
### Highlights
- Added LuaDist integration.
- Added live coding support for GSL-shell.
- Added support for project settings.
- Added filetree operations.
- Added Busted interpreter.
### Special thanks
- To Jayanth Acharya for SciTeLuaIDE color scheme.
- To Mike Richards for adding edge handling and styles.
- To [adamdmoss](https://github.com/adamdmoss) for Mobdebug API update.
### Improvements
- Added live coding support for GSL-shell (closes #239).
- Added support for product-specific links in the Help menu.
- Added 'edge' style to the color schemes (ref #237).
- Added ability to set 'edge' style properties individually (ref #237).
- Add edge to styles
- Add fold margin checker color to styles
- Add edge line and fold margin checker color
- Added changing directory when launching on Linux (closes #157).
- Added setting PATH for LfW to allow loading of DLL dependencies.
- Added logic to set architecture dynamically for luadist (ref #225).
- Added luadist bootstrap dependencies for Linux (ref #225).
- Added option to load luadist as a module (ref #225).
- Added luadist bootstrap dependencies for OSX (ref #225).
- Added proxy dll for Lua 5.2 (ref #225).
- Added luadist bootstrap dependencies for Windows (ref #225).
- Added package GetInterpreters method (ref #166, #225).
- Added package AddConsoleAlias/RemoveConsoleAlias methods (ref #166, #225).
- Added version property to the Lua interpreters.
- Added new location for Marmalade Quick v7+ and s3e path logic (fixes #226).
- Added directory creation (if needed) to file saving.
- Added support for symlinks in the filetree (with recursion protection).
- Added package AddConfig/RemoveConfig methods (ref #166).
- Added package GetProject method (ref #166).
- Added package onProjectPreLoad method (ref #166).
- Added workaround for conflict with Scintilla shortcuts on Linux.
- Added 'Open with Default Program' to file tree operations (ref #123).
- Added toggling directory on Enter (ref #123).
- Added 'Copy Full Path' to file tree operations (ref #123).
- Added deleting file/directory to file tree operations (ref #123).
- Added processing of packages from `$HOME/.zbstudio/packages` folder (#166).
- Added 'New File' and 'New Directory' to file operations (ref #123).
- Added error reporting for failed rename operations (ref #123).
- Added re-opening editor tabs affected by directory move/rename (ref #123).
- Added package FindDocumentsByPartialPath method (ref #166).
- Added existing file overwrite confirmation when renaming (ref #123).
- Added existing file overwrite confirmation when saving.
- Added creating intermediate directories during file rename (ref #123).
- Added in-place editing of file and folder names (ref #123).
- Added refreshing editor tab after drag-n-drop operation (ref #123).
- Added drag-n-drop operation to move files in the project tree (ref #123).
- Added package AddMarker/RemoveMarker methods (ref #166).
- Added package GetStatusBar method (ref #166).
- Added package GetDocuments and document methods (ref #166).
- Added `EscapeMagic` function to escape magic characters.
- Added SciTeLuaIDE color scheme (thanks to Jayanth Acharya).
- Changed glslc option to reflect new version
- Disabled compilation check for scratchpad when `skipcompile` is set (ref #239).
- Disabled output activation for messages redirected to Console (ref #225).
- Disabled commenting for file types that don't specify line comments.
- Moved restoring project before loading files (ref #107).
- Reorganized loading configuration files (ref #107).
- Removed 'file no longer exists' message after moving opened files (ref #123).
- Removed some of the snippets as they are available as plugins.
- Store os specific clibs path to make it available to plugins.
- Tidy up estrela tools a bit (remove key strokes from cgc, remove luxinia res viewer, rename perforce files to get loaded again)
- Updated README.
- Updated samples with missing indicator constants (closes #243).
- Updated OSX executables and added 'fake' proxy for lua-dist support (ref #225).
- Updated handling of case-insensitive names during debugging on OSX (Mobdebug v0.545).
- Updated package onEditorPreSave to be called on SaveAs events (ref #166).
- Updated icon bundle to eliminate large icons.
- Updated application icon to a bit brighter one on OSX (closes #196).
- Updated build script on OSX to not require 10.6 SDK (closes #231).
- Updated menu definitions for consistency.
- Updated use of `unpack` for consistency and Lua 5.2 compatibility.
- Updated 'Open with Default Program' on Windows to work with spaces in names (#123).
- Updated cmake installation script to install to '/Applications' on OSX.
- Updated OSX build script to revert wxwidgets commit to fix auto-complete crash.
- Updated `Start debugging` hint to clarify.
- Updated single-click toggle to allow rename/move directories (ref #123).
- Updated normalization flags as some path parts were changed to dots.
- Updated editor tab processing using FindDocument method.
- Updated shortcut for Replace All to avoid conflict on OSX (fixes #220).
- Updated `SetDocumentModified` to use current tab text.
### Fixes
- Fixed values 'captured' by redirected 'print' and not collected (fixes #240).
- Fixed typo in fold style definition (ref #237).
- Fixed console output being limited in addition to stack result limit.
- Fixed hang in auto-complete on expressions involving '...' (fixes #235).
- Fixed auto-complete for string values (broken by 933aacc2).
- Fixed crash when LUA_DEV environmental variable is not set (fixes #228).
- Fixed cmake cache filename (ref #225).
- Fixed incorrect UTF-8 sequence in UTF-8 validity check.
- Fixed Un/Comment menu for Output/Console windows.
- Fixed format of the file name reported after compilation errors.
- Fixed jumping to compilation error (if any) after Run/Debug.
- Fixed disabling 'Open with Default Program' on OSX (ref #123).
- Fixed file tree update after changes on OSX (ref #123).
- Fixed copying full path on OSX (ref #123).
- Fixed 'Open with Default Program' for paths with spaces on Windows (ref #123).
- Fixed folding issue (caused by `math.mod` not available in LuaJIT).
- Fixed debugger marker calculations to avoid marker conflicts.
- Fixed color references in marker config examples.
- Fixed Step Over/Out to stay in the same coroutine; Mobdebug 0.543 (closes #217).
- Fixed case sensitivity in matching of file name in error messages (fixes #216).
- Fixed tab text after SaveAs and loading files into the same tab.
## v0.39 (Oct 06 2013)
### Highlights

View File

@@ -2,8 +2,15 @@
[ZeroBrane Studio](http://studio.zerobrane.com/) is a lightweight Lua IDE with code completion, syntax
highlighting, remote debugger, code analyzer, live coding, and debugging
support for several Lua engines (LuaJIT, Löve 2D, Moai, Gideros, Corona, Marmalade Quick,
MobileLua, GSL-shell, and others). It originated from the [Estrela Editor](http://www.luxinia.de/index.php/Estrela/).
support for several Lua engines (LuaJIT,
[Löve 2D](http://notebook.kulchenko.com/zerobrane/love2d-debugging),
[Moai](http://notebook.kulchenko.com/zerobrane/moai-debugging-with-zerobrane-studio),
[Gideros](http://notebook.kulchenko.com/zerobrane/gideros-debugging-with-zerobrane-studio-ide),
[Corona](http://notebook.kulchenko.com/zerobrane/debugging-and-live-coding-with-corona-sdk-applications-and-zerobrane-studio),
[Marmalade Quick](http://notebook.kulchenko.com/zerobrane/marmalade-quick-debugging-with-zerobrane-studio),
[Cocos2d-x](http://notebook.kulchenko.com/zerobrane/cocos2d-x-simulator-and-on-device-debugging-with-zerobrane-studio),
[GSL-shell](http://notebook.kulchenko.com/zerobrane/gsl-shell-debugging-with-zerobrane-studio),
MobileLua, and others). It originated from the [Estrela Editor](http://www.luxinia.de/index.php/Estrela/).
## Features
@@ -11,20 +18,32 @@ MobileLua, GSL-shell, and others). It originated from the [Estrela Editor](http:
* Small, portable, and cross-platform (Windows, Mac OSX, and Linux).
* Auto-completion for functions, keywords, and custom APIs.
* Interactive console to directly test code snippets with local and remote execution.
* Integrated debugger (with support for local and remote debugging).
* Live coding with Lua ([demo](http://notebook.kulchenko.com/zerobrane/live-coding-in-lua-bret-victor-style)), Löve 2D ([demo](http://notebook.kulchenko.com/zerobrane/live-coding-with-love)), Gideros ([demo](http://notebook.kulchenko.com/zerobrane/gideros-live-coding-with-zerobrane-studio-ide)), Moai ([demo](http://notebook.kulchenko.com/zerobrane/live-coding-with-moai-and-zerobrane-studio)), and Corona SDK ([demo](http://notebook.kulchenko.com/zerobrane/debugging-and-live-coding-with-corona-sdk-applications-and-zerobrane-studio)).
* Support for plugin-like components:
- specs (spec/): file syntax, lexer, keywords (e.g. glsl);
- apis (api/): for code-completion and tool-tips;
- interpreters (interpreters/): how a project is run;
- config (cfg/): contains style and basic editor settings;
- tools (tools/): additional tools (e.g. DirectX/Cg shader compiler...).
* Integrated debugger with local and [remote debugging](http://studio.zerobrane.com/doc-remote-debugging.html) for Lua 5.1,
[Lua 5.2](http://studio.zerobrane.com/doc-lua52-debugging.html),
[LuaJIT](http://studio.zerobrane.com/doc-luajit-debugging.html),
and [other Lua engines](http://studio.zerobrane.com/documentation.html#debugging).
* [Live coding](http://studio.zerobrane.com/documentation.html#live_coding)
with [Lua](http://notebook.kulchenko.com/zerobrane/live-coding-in-lua-bret-victor-style),
[Löve 2D](http://notebook.kulchenko.com/zerobrane/live-coding-with-love),
[Gideros](http://notebook.kulchenko.com/zerobrane/gideros-live-coding-with-zerobrane-studio-ide),
[Moai](http://notebook.kulchenko.com/zerobrane/live-coding-with-moai-and-zerobrane-studio),
[Corona SDK](http://notebook.kulchenko.com/zerobrane/debugging-and-live-coding-with-corona-sdk-applications-and-zerobrane-studio),
GSL-shell, and other engines.
* Several ways to extend the current functionality:
- specs (`spec/`): specifications for file syntax, lexer, and keywords;
- apis (`api/`): descriptions for [code completion and tooltips](http://studio.zerobrane.com/doc-api-auto-complete.html);
- interpreters (`interpreters/`): components for setting debugging and run-time project environment;
- packages (`packages/`): [plugins](http://studio.zerobrane.com/doc-plugin.html) that provide additional functionality;
- config (`cfg/`): settings for styles, color themes, and other preferences;
- translations (`cfg/i18n/`): [translations](http://studio.zerobrane.com/doc-translation.html) of the menus and messages to other languages;
- tools (`tools/`): additional tools.
## Documentation
* A [short and simple overview](http://studio.zerobrane.com/doc-getting-started.html) for those who are new to this development environment.
* A list of [frequently asked questions](http://studio.zerobrane.com/doc-faq.html) about the IDE.
* [Tutorials and demos](http://studio.zerobrane.com/tutorials.html) that cover debugging and live coding for different environments.
* [Tips and tricks](http://studio.zerobrane.com/doc-tips-and-tricks.html).
## Screenshot

View File

@@ -153,18 +153,31 @@ memoryBarrierShared = fn "control ordering of memory transactions issued by shad
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)",
imageAtomicIncWrap = fn "performs atomic operation on individual texels returns new value. - (uint)(imageN, intN coord, [int sample], uint data)",
imageAtomicDecWrap = fn "performs atomic operation on individual texels returns new value. - (uint)(imageN, intN coord, [int sample], uint data)",
imageAtomicAnd = fn "performs atomic operation on individual texels returns new value. - (uint)(imageN, intN coord, [int sample], uint data)",
imageAtomicOr = fn "performs atomic operation on individual texels returns new value. - (uint)(imageN, intN coord, [int sample], uint data)",
imageAtomicXor = fn "performs atomic operation on individual texels returns new value. - (uint)(imageN, intN coord, [int sample], uint data)",
imageAtomicExchange = fn "performs atomic operation on individual texels returns new value. - (uint)(imageN, intN coord, [int sample], uint data)",
imageAtomicCompSwap = fn "performs atomic operation on individual texels returns new value. - (uint)(imageN, intN coord, [int sample], uint data)",
imageAtomicAdd = fn "performs atomic operation on individual texels returns old value. - (uint)(imageN, intN coord, [int sample], uint data)",
imageAtomicMin = fn "performs atomic operation on individual texels returns old value. - (uint)(imageN, intN coord, [int sample], uint data)",
imageAtomicMax = fn "performs atomic operation on individual texels returns old value. - (uint)(imageN, intN coord, [int sample], uint data)",
imageAtomicIncWrap = fn "performs atomic operation on individual texels returns old value. - (uint)(imageN, intN coord, [int sample], uint data)",
imageAtomicDecWrap = fn "performs atomic operation on individual texels returns old value. - (uint)(imageN, intN coord, [int sample], uint data)",
imageAtomicAnd = fn "performs atomic operation on individual texels returns old value. - (uint)(imageN, intN coord, [int sample], uint data)",
imageAtomicOr = fn "performs atomic operation on individual texels returns old value. - (uint)(imageN, intN coord, [int sample], uint data)",
imageAtomicXor = fn "performs atomic operation on individual texels returns old value. - (uint)(imageN, intN coord, [int sample], uint data)",
imageAtomicExchange = fn "performs atomic operation on individual texels returns old value. - (uint)(imageN, intN coord, [int sample], uint data)",
imageAtomicCompSwap = fn "performs atomic operation on individual texels returns old value. - (uint)(imageN, intN coord, [int sample], uint data)",
imageStore = fn "stores the texel at the coordinate. - ()(imageN, intN coord, [int sample], vecN data)",
imageLoad = fn "loads the texel at the coordinate. - (vecN)(imageN, intN coord, [int sample])",
imageSize = fn "returns the size of the image. - (ivecN)(imageN)",
atomicCounterIncrement = fn "increments counter and returns old value. - (uint)(atomic_uint)",
atomicCounterDecrement = fn "decrements counter and returns old value. - (uint)(atomic_uint)",
atomicCounter = fn "returns current counter value. - (uint)(atomic_uint)",
atomicMin = fn "performs atomic operation on memory location (ssbo/shared) returns old value. - (uint)(inout uint mem, uint data)",
atomicMax = fn "performs atomic operation on memory location (ssbo/shared) returns old value. - (uint)(inout uint mem, uint data)",
atomicAdd = fn "performs atomic operation on memory location (ssbo/shared) returns old value. - (uint)(inout uint mem, uint data)",
atomicAnd = fn "performs atomic operation on memory location (ssbo/shared) returns old value. - (uint)(inout uint mem, uint data)",
atomicOr = fn "performs atomic operation on memory location (ssbo/shared) returns old value. - (uint)(inout uint mem, uint data)",
atomicXor = fn "performs atomic operation on memory location (ssbo/shared) returns old value. - (uint)(inout uint mem, uint data)",
atomicExchange = fn "performs atomic operation on memory location (ssbo/shared) returns old value. - (uint)(inout uint mem, uint data)",
atomicCompSwap = fn "performs atomic operation on memory location (ssbo/shared) returns old value. - (uint)(inout uint mem, uint data)",
textureSize = fn "returns the size of the texture (no lod required: Rect, MS and Buffer). - (intN)(samplerN, [int lod])",
textureQueryLod = fn "returns the lod values for a given coordinate. - (vec2)(samplerN, vecN coord)",
@@ -234,6 +247,7 @@ local keyw =
gl_NumWorkGroups gl_WorkGroupSize gl_WorkGroupID gl_LocalInvocationID gl_GlobalInvocationID gl_LocalInvocationIndex
local_size_x local_size_y local_size_z
gl_BaseVertexARB gl_BaseInstanceARB gl_DrawIDARB
bindless_sampler bound_sampler bindless_image bound_image early_fragment_tests
coherent volatile restrict readonly writeonly
image1D image2D image3D image2DRect imageCube imageBuffer image1DArray image2DArray imageCubeArray image2DMS image2DMSArray

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -1,9 +1,15 @@
-- Copyright 2013 Paul Kulchenko, ZeroBrane LLC
-- Copyright 2013-14 Paul Kulchenko, ZeroBrane LLC
return {
ads = {
type = "class",
childs = {
init = {
type = "method",
description = "Initialise the ad system, must be called before the ad system can be used.",
args = "()",
returns = "()",
},
isAvailable = {
type = "method",
description = "Checks availability of ads.",
@@ -27,6 +33,12 @@ return {
analytics = {
type = "class",
childs = {
endSession = {
type = "method",
description = "Ends a Flurry analytics session.",
args = "()",
returns = "()",
},
isAvailable = {
type = "method",
description = "Checks availability of analytics.",
@@ -47,7 +59,7 @@ return {
},
startSession = {
type = "method",
description = "Starts a Flurry analytics session.\nyour app",
description = "Starts a Flurry analytics session.",
args = "(apiKey: string)",
returns = "()",
},
@@ -263,7 +275,7 @@ return {
},
isAvailable = {
type = "method",
description = "Checks available of in-app purchasing.",
description = "Checks availability of in-app purchasing.",
args = "()",
returns = "(boolean)",
},
@@ -519,6 +531,10 @@ return {
director = {
type = "class",
childs = {
addNodesToScene = {
type = "value",
description = "Whether or not the Director should automatically add newly-created display objects to the current scene.\nThe default value is true.",
},
addScene = {
type = "method",
description = "Add a Scene object to the Director. The added Scene object will become the current scene.\nTypically this function is not called directly: instead, the app calls director:createScene() which both creates the new Scene\nobject and adds it to the Director.",
@@ -536,84 +552,84 @@ return {
description = "Create an animation, specifying arbitrary input values.\nSee the Objects reference for details of all properties and functions on the Animation object.",
valuetype = "animation",
args = "(values: table)",
returns = "(object)",
returns = "(animation)",
},
createAtlas = {
type = "method",
description = "Create a texture atlas. Two different input types are permitted:\n| ``director:createAtlas(filename)``\n| ``director:createAtlas(values)``\nSee the Objects reference for details of all properties and functions on the Atlas object.",
valuetype = "atlas",
args = "(filename: string, values: table)",
returns = "(object)",
returns = "(atlas)",
},
createBBox = {
type = "method",
description = "Create a bounding box object, from x and y bounds. The object simply copies these values into the properties\nxMin, xMax, yMin, yMax respectively.\n----------\n**Scene functions**.",
valuetype = "box",
args = "(xMin: number, xMax: number, yMin: number, yMax: number)",
returns = "(object)",
returns = "(box)",
},
createCircle = {
type = "method",
description = "Create a Circle node. Two different input types are permitted:\n| ``director:createCircle(x, y, radius)``\n| ``director:createCircle(values)``\nSee the Objects reference for details of all properties and functions on the Circle object.",
valuetype = "circle",
args = "(x: number, y: number, radius: number, values: table)",
returns = "(object)",
returns = "(circle)",
},
createFont = {
type = "method",
description = "Create a Font object. Two different input types are permitted:\n| ``director:createFont(filename)``\n| ``director:createFont(values)``\nSee the Objects reference for details of all properties and functions on the Font object.",
valuetype = "font",
args = "(filename: string, values: table)",
returns = "(object)",
returns = "(font)",
},
createLabel = {
type = "method",
description = "Create a Label node. Two different input types are permitted:\n| ``director:createLabel(x, y, text, font)``\n| ``director:createLabel(values)``\nSee the Objects reference for details of all properties and functions on the Label object.",
valuetype = "label",
args = "(x: number, y: number, text: string, font: object or string, values: table)",
returns = "(object)",
returns = "(label)",
},
createLines = {
type = "method",
description = "Create a Lines node. Two different input types are permitted:\n| ``director:createLines(x, y, coords)``\n| ``director:createLines(values)``\nSee the Objects reference for details of all properties and functions on the Lines object.",
valuetype = "lines",
args = "(x: number, y: number, coords: table, values: table)",
returns = "(object)",
returns = "(lines)",
},
createNode = {
type = "method",
description = "Create a Node object, specifying a table of arbitrary input values.\nSee the Objects reference for details of all properties and functions on the Node object.",
valuetype = "node",
args = "(values: table)",
returns = "(object)",
returns = "(node)",
},
createParticles = {
type = "method",
description = "Create a Particles node. Three different input types are permitted:\n| ``director:createParticles(plist)``\n| ``director:createParticles(numParticles)``\n| ``director:createParticles(values)``\nThis file is output from the ParticleDesigner tool, or similar.\nThe app should then set up all other member variables explicitly.\nwritable properties of the Particles object. Additionally, the user \ncan specify the 'source' property, which can be a full pathname to a \ntexture, or an existing Atlas object. For example::\n-- Specify texture from filename\nlocal p1 = director:createParticles( { totalParticles=500, source=\"particles/fire.png\" } )\n-- Specify texture from Atlas object\nlocal atlas = director:createAtlas(\"textures/beachball.png\")\nlocal p2 = director:createParticles( { totalParticles=500, source=atlas } )\nSee the Objects reference for details of all properties and functions on the Particles object.",
valuetype = "particles",
args = "(plist: string, numParticles: number, values: table)",
returns = "(object)",
returns = "(particles)",
},
createRectangle = {
type = "method",
description = "Create a Rectangle node. Two different input types are permitted:\n| ``director:createRectangle(x, y, w, h)``\n| ``director:createRectangle(values)``\nSee the Objects reference for details of all properties and functions on the Rectangle object.",
valuetype = "rectangle",
args = "(x: number, y: number, w: number, h: number, values: table)",
returns = "(object)",
returns = "(rectangle)",
},
createScene = {
type = "method",
description = "Create a scene node, and set it to be the director's current scene.\nNote that no transition occurs from any previous scene, and no scene events are thrown.",
valuetype = "scene",
args = "()",
returns = "(object)",
returns = "(scene)",
},
createSprite = {
type = "method",
description = "Create a Sprite node. Two different input types are permitted:\n| ``director:createSprite(x, y, source)``\n| ``director:createSprite(values)``\nSee the Objects reference for details of all properties and functions on the Sprite object.",
valuetype = "sprite",
args = "(x: number, y: number, source: number or object, values: table)",
returns = "(object)",
returns = "(sprite)",
},
displayCenterX = {
type = "value",
@@ -637,6 +653,10 @@ return {
args = "()",
returns = "(object)",
},
isAlphaInherited = {
type = "value",
description = "Whether or not node alpha (and strokeAlpha) should be inherited (propogated) through the scene graph.\nThe default value is true.",
},
moveToScene = {
type = "method",
description = "Move to a new scene. The new scene receives the following events:\n- setUp - Called immediately, only if the new scene is not already set up.\n- enterPreTransition - Called BEFORE any transition, immediately after the check for sending of the setUp event.\n- enterPostTransition - Called AFTER any transition has completed.\nThe old scene receives the following events:\n- exitPreTransition - Called BEFORE any transition, immediately after the enterPreTransition event is sent to the new scene.\n- tearDown - Called AFTER any transition has completed, if the scene is currently set up.\n- exitPostTransition - Called AFTER any transition has completed, immediately after the tearDown event.\nThe options table can take the following properties:\n- transitionType (string) - Valid values are:\n- \"rotoZoom\"\n- \"jumpZoom\"\n- \"moveInR\"\n- \"moveInT\"\n- \"moveInB\"\n- \"slideInL\"\n- \"slideInR\"\n- \"slideInB\"\n- \"slideInT\"\n- \"shrinkGrow\"\n- \"flipX\"\n- \"flipY\"\n- \"flipAngular\"\n- \"zoomFlipX\"\n- \"zoomFlipY\"\n- \"zoomFlipAngular\"\n- \"crossFade\"\n- \"turnOffTiles\"\n- \"splitCols\"\n- \"splitRows\"\n- \"fadeTR\"\n- \"fadeBL\"\n- \"fadeUp\"\n- \"fadeDown\"\n- \"progressRadialCCW\"\n- \"progressRadialCW\"\n- \"progressHorizontal\"\n- \"progressVertical\"\n- \"progressInOut\"\n- \"progressOutIn\"\n- \"fade\"\n- \"pageTurn\"\nYou'll have to experiment with them to find out what they really do! \n- transitionTime (number) - The duration of the transition, in seconds.\n----------\n**Node functions**.",
@@ -666,6 +686,12 @@ return {
facebook = {
type = "class",
childs = {
isAvailable = {
type = "method",
description = "Checks availability of the Facebook API.",
args = "()",
returns = "(boolean)",
},
login = {
type = "method",
description = "Log in to Facebook.\nDisplays the Facebook login dialog. If the user has already put in\ntheir Facebook details then this dialog may not be displayed.",
@@ -743,7 +769,7 @@ return {
description = "The null function allows one to specify a null value in an associative array (which is otherwise\ndiscarded if you set the value with 'nil' in Lua).",
valuetype = "null",
args = "()",
returns = "(object)",
returns = "(null)",
},
},
},
@@ -856,7 +882,7 @@ return {
description = "Add a timed event to this node.",
valuetype = "timer",
args = "(funcortable: function or table, period: number, iterations: number, delay: number)",
returns = "(object)",
returns = "(timer)",
},
alpha = {
type = "value",
@@ -906,6 +932,18 @@ return {
args = "()",
returns = "(object)",
},
getPointInLocalSpace = {
type = "method",
description = "Given a point in the world (scene) space, return a point in the node's local space.\nNote that for this function to behave as expected, the node's local transform must\nbe up-to-date. For example, if trying to call this function directly after creating a node,\nyou should call Node:sync() to update the local transform first.\n:return: Returns an x,y pair for the point in local (node) space.",
args = "(x: number, y: number)",
returns = "()",
},
getPointInWorldSpace = {
type = "method",
description = "Given a point in the node's local space, return a point in the world (scene) space.\nNote that for this function to behave as expected, the node's local transform must\nbe up-to-date. For example, if trying to call this function directly after creating a node,\nyou should call Node:sync() to update the local transform first.\n:return: Returns an x,y pair for the point in world (scene) space.",
args = "(x: number, y: number)",
returns = "()",
},
getTimersTimeScale = {
type = "method",
description = "Get the time scaling factor currently applied to all timers on this node.",
@@ -1026,6 +1064,12 @@ return {
args = "(f: number)",
returns = "()",
},
sync = {
type = "method",
description = "Synchronises the Cocos2d-x data with the Quick data for this Node. In most scenarios you do\nnot need to explicitly call this function - it is done automatically across the scene, as\npart of the Director's update.",
args = "()",
returns = "()",
},
timers = {
type = "value",
description = "The list (table) of timers attached to this node. The table can be queried for its length, and can be iterated over, but must\nnot be manipulated in any other way. Attempting to insert or remove elements from the table will result in undefined and almost\ncertainly undesirable behaviour.",
@@ -1082,36 +1126,6 @@ return {
},
},
},
nui = {
type = "class",
childs = {
createWebView = {
type = "method",
description = "Create a fullscreen or windowed web view. Two different input types are permitted:\n| ``director:createWebView(url)``\n| ``director:createWebView(values)``\nExamples::\n-- Create a fullscreen web view\nlocal view1 = director:createWebView(\"http://www.google.com/news\")\n-- Create a windowed web view\nlocal view2 = director:createWebView( {\nx=0, y=0, \nw=200, h=100, \ntransparentBackground=true, \nurl=\"http://www.google.com/news\", \n} )",
valuetype = "webView",
args = "(url: string, values: table)",
returns = "(object)",
},
isReadStringAvailable = {
type = "method",
description = "Check whether \"readString\" functionality is available on the target device.\nNote that in Quick 1.0, \"readString\" functionality is not supported on Mac, so this function will return false.",
args = "()",
returns = "(boolean)",
},
isWebViewAvailable = {
type = "method",
description = "Check whether web views are available on the target device.",
args = "()",
returns = "(boolean)",
},
readString = {
type = "method",
description = "Creates a modal native dialog box for inputting a text string. The dialog box displays the string being entered, and\nthe native device Input Method Entry (IME) mechanism it used to capture the string (for mobile devices, this is usually\nin the form of a \"soft keyboard\" that slides onto the screen for touch-typing).\nThe user must specify a \"prompt\" string, that will be used as a title for the native dialog box. The user may optionally\nspecify a \"mode\" string, which can be used to configure the IME (e.g. the type of touch keyboard) depending on the type\nof string being captured - e.g to switch to an optimised touch keyboard for inputting URLs, if the device supports it.\nThe default is to use the standard IME (e.g. the standard type of touch keyboard)\nFinally, the user can optionally specify a \"default\" string that will pre-populate the dialog box. The user must then\nuse the IME to edit the string if required.\nAll strings (both input and output) are in UTF8 format.\n- \"email\" - Optimise for email address entry.\n- \"number\" - Optimise for number entry.\n- \"password\" - Optimise for password entry (e.g. hide characters after typing).\n- \"url\" - Optimise for URL entry.\n- \"\" or no input - Standard entry.\notherwise the return value is always of type 'string', even if the 'mode' input is specified as 'number'.",
args = "(promptUTF8: string [, mode: string] [, defaultUTF8: string])",
returns = "(string or nil)",
},
},
},
particles = {
type = "class",
childs = {
@@ -1163,6 +1177,12 @@ return {
type = "value",
description = "The random variance, in degrees, to add to the final spin of each particle. The final spin\nof each particle will be a random value in the range [endSpin - endSpinVar, endSpin + endSpinVar].\nThe default value is 0.",
},
isActive = {
type = "method",
description = "Returns true only if there are any particles still alive.",
args = "()",
returns = "(boolean)",
},
isFull = {
type = "method",
description = "Returns true only if the number of living particles is equal to the total number of particles\npermitted by the particle system ('totalParticles').",
@@ -1446,70 +1466,70 @@ return {
description = "Creates a distance joint that constrains the two attached bodies to maintain a constant distance defined\nby the two anchor points. Two different input types are permitted:\n| ``physics:createDistanceJoint(nodeA, nodeB, x1, y1, x2, y2, collideConnected)``\n| ``physics:createDistanceJoint(values)``\nSupported properties, beyond those of the default constructor, include:\n- length (number) - The distance to maintain between the joints\n- frequency (number) - The frequency of any oscillation\n- dampingRatio (number) - The damping ratio of any oscillation",
valuetype = "jointDistance",
args = "(nodeA: object, nodeB: object [, x1: number] [, y1: number] [, x2: number] [, y2: number] [, collideConnected: boolean], values: table)",
returns = "(object)",
returns = "(jointDistance)",
},
createFrictionJoint = {
type = "method",
description = "Creates a friction joint: a special kind of revolute / prismatic joint that resists motion, and provides\n2D translational and angular friction. Two different input types are permitted:\n| ``physics:createFrictionJoint(nodeA, nodeB, collideConnected)``\n| ``physics:createFrictionJoint(values)``",
valuetype = "jointFriction",
args = "(nodeA: object, nodeB: object [, collideConnected: boolean], values: table)",
returns = "(object)",
returns = "(jointFriction)",
},
createGearJoint = {
type = "method",
description = "Creates a gear joint that can only connect revolute and/or prismatic joints.\nLike the pulley ratio, you can specify a gear ratio. \nHowever, in this case the gear ratio can be negative. \nAlso keep in mind that when one joint is a revolute joint (angular) and the other joint is prismatic (translation), \nthen the gear ratio will have units of length or one over length.\nCaution: Deleting one of the connected joints automatically deletes this joint.\nCaution: The \"nodeB\" of both the connected joints must not be the same, and must be non-static.\nTwo different input types are permitted:\n| ``physics:createGearJoint(jointA, jointB, collideConnected)``\n| ``physics:createGearJoint(values)``",
valuetype = "jointGear",
args = "(jointA: object, jointB: object [, ratio: number] [, collideConnected: boolean], values: table)",
returns = "(object)",
returns = "(jointGear)",
},
createPrismaticJoint = {
type = "method",
description = "Creates a prismatic (piston) joint. Two different input types are permitted:\n| ``physics:createPrismaticJoint(nodeA, nodeB, x, y, localAxisX, localAxisY, collideConnected)``\n| ``physics:createPrismaticJoint(values)``",
valuetype = "jointPrismatic",
args = "(nodeA: object, nodeB: object, x: number, y: number, localAxisX: number, localAxisY: number [, collideConnected: boolean], values: table)",
returns = "(object)",
returns = "(jointPrismatic)",
},
createPulleyJoint = {
type = "method",
description = "Creates a pulley joint that attaches two bodies with an imaginary rope whose length remains constant: if one body is pulled down, the other one will move up.\nTwo different input types are permitted:\n| ``physics:createPulleyJoint(nodeA, nodeB, x1, y1, x2, y2, collideConnected)``\n| ``physics:createPulleyJoint(values)``",
valuetype = "jointPulley",
args = "(nodeA: object, nodeB: object, groundAnchorAX: number, groundAnchorAY: number, groundAnchorBX: number, groundAnchorBY: number [, anchorAX: number] [, anchorAY: number] [, anchorBX: number] [, anchorBY: number] [, ratio: number] [, collideConnected: boolean], values: table)",
returns = "(object)",
returns = "(jointPulley)",
},
createRevoluteJoint = {
type = "method",
description = "Creates a revolute (pivot) joint that constrains the two attached bodies to rotate about a point.\nTwo different input types are permitted:\n| ``physics:createRevoluteJoint(nodeA, nodeB, x, y, collideConnected)``\n| ``physics:createRevoluteJoint(values)``",
valuetype = "jointRevolute",
args = "(nodeA: object, nodeB: object, x: number, y: number [, collideConnected: boolean], values: table)",
returns = "(object)",
returns = "(jointRevolute)",
},
createRopeJoint = {
type = "method",
description = "Creates a rope joint that restricts the maximum distance between two points. This can be useful to prevent chains of bodies from stretching, even under high load.\nTwo different input types are permitted:\n| ``physics:createRopeJoint(nodeA, nodeB, x1, y1, x2, y2, collideConnected)``\n| ``physics:createRopeJoint(values)``",
valuetype = "jointRope",
args = "(nodeA: object, nodeB: object [, anchorAX: number] [, anchorAY: number] [, anchorBX: number] [, anchorBY: number], values: table)",
returns = "(object)",
returns = "(jointRope)",
},
createTouchJoint = {
type = "method",
description = "Creates a \"touch\" (mouse) joint that attaches a body to the world through a spring.\nTwo different input types are permitted:\n| ``physics:createTouchJoint(nodeA, dampingRatio, frequency, maxForce)``\n| ``physics:createTouchJoint(values)``",
valuetype = "jointTouch",
args = "(nodeA: object [, dampingRatio: number] [, frequency: number] [, maxForce: number], values: table)",
returns = "(object)",
returns = "(jointTouch)",
},
createWeldJoint = {
type = "method",
description = "Creates a weld joint that literaly welds the two attached body in a point.\nTwo different input types are permitted:\n| ``physics:createWeldJoint(nodeA, nodeB, x, y, collideConnected)``\n| ``physics:createWeldJoint(values)``",
valuetype = "jointWeld",
args = "(nodeA: object, nodeB: object [, x: number] [, y: number] [, collideConnected: boolean], values: table)",
returns = "(object)",
returns = "(jointWeld)",
},
createWheelJoint = {
type = "method",
description = "Creates a wheel joint that combines a piston and a pivot joint. Two different input types are permitted:\n| ``physics:createWheelJoint(nodeA, nodeB, localAxisX, localAxisY, ax, ay, bx, by, collideConnected)``\n| ``physics:createWheelJoint(values)``",
valuetype = "jointWheel",
args = "(nodeA: object, nodeB: object, localAxisX: number, localAxisY: number [, ax: number] [, ay: number] [, bx: number] [, by: number] [, collideConnected: boolean], values: table)",
returns = "(object)",
returns = "(jointWheel)",
},
debugDraw = {
type = "value",
@@ -1636,7 +1656,7 @@ return {
},
},
},
jointdistance = {
jointDistance = {
type = "class",
childs = {
dampingRatio = {
@@ -1654,7 +1674,7 @@ return {
},
inherits = "joint",
},
jointfriction = {
jointFriction = {
type = "class",
childs = {
maxForce = {
@@ -1668,7 +1688,7 @@ return {
},
inherits = "joint",
},
jointgear = {
jointGear = {
type = "class",
childs = {
joint1 = {
@@ -1686,7 +1706,7 @@ return {
},
inherits = "joint",
},
jointprismatic = {
jointPrismatic = {
type = "class",
childs = {
jointSpeed = {
@@ -1728,7 +1748,7 @@ return {
},
inherits = "joint",
},
jointpulley = {
jointPulley = {
type = "class",
childs = {
lengthA = {
@@ -1746,7 +1766,7 @@ return {
},
inherits = "joint",
},
jointrevolute = {
jointRevolute = {
type = "class",
childs = {
jointAngle = {
@@ -1788,7 +1808,7 @@ return {
},
inherits = "joint",
},
jointrope = {
jointRope = {
type = "class",
childs = {
maxLength = {
@@ -1798,7 +1818,7 @@ return {
},
inherits = "joint",
},
jointtouch = {
jointTouch = {
type = "class",
childs = {
dampingRatio = {
@@ -1822,7 +1842,7 @@ return {
},
inherits = "joint",
},
jointweld = {
jointWeld = {
type = "class",
childs = {
dampingRatio = {
@@ -1836,7 +1856,7 @@ return {
},
inherits = "joint",
},
jointwheel = {
jointWheel = {
type = "class",
childs = {
jointSpeed = {
@@ -1874,6 +1894,36 @@ return {
},
inherits = "joint",
},
scene = {
type = "class",
childs = {
releaseAnimation = {
type = "method",
description = "Clears the scene's references to the specified Animation object. If the app maintains any additional\nreferences to this objects then it will persist, otherwise it will become ready for garbage \ncollection.",
args = "(animation: object)",
returns = "()",
},
releaseAtlas = {
type = "method",
description = "Clears the scene's references to the specified Atlas object. If the app maintains any additional\nreferences to this objects then it will persist, otherwise it will become ready for garbage \ncollection.",
args = "(atlas: object)",
returns = "()",
},
releaseFont = {
type = "method",
description = "Clears the scene's references to the specified Font object. If the app maintains any additional\nreferences to this objects then it will persist, otherwise it will become ready for garbage \ncollection.",
args = "(font: object)",
returns = "()",
},
releaseResources = {
type = "method",
description = "Clears the scene's references to all owned Atlas, Animation and Font objects. If the app \nmaintains additional references to any specific objects of these types then they will persist, \notherwise the objects will become ready for garbage collection.",
args = "()",
returns = "()",
},
},
inherits = "node",
},
sprite = {
type = "class",
childs = {
@@ -1948,7 +1998,7 @@ return {
description = "Add a global timed event.",
valuetype = "timer",
args = "(funcortable: function or table, period: number, iterations: number, delay: number)",
returns = "(object)",
returns = "(timer)",
},
debugTime = {
type = "value",
@@ -2355,7 +2405,7 @@ return {
},
to = {
type = "method",
description = "Tween a series of node properties over time.\nThe final property values are specified in the params table. To customize the\ntween, you can optionally specify the following non-animating properties in params:\n* params.time (number) - The duration of the tween, in seconds. Default value is 0.5. The duration refers\nto the length of a 'cycle'; see the 'mode' parameter below.\n* params.delay (number) - Any delay in seconds before the tween begins. Default value is 0. If this value is\ngreater than 0, then this period must elapse before any properties start tweening. The 'onStart' callback\nis called only when this period has elapsed.\n* params.delta (boolean) - Whether or not to interpret the specified values as absolute, or relative to the\ncurrent values. The default is false, meaning absolute values. If true, the 'current' values are those\nat the point at which any 'delay' period has elapsed.\n* params.mode (string) - Can be 'clamp', 'repeat' or 'mirror'. The default value is 'clamp'.\n* \"clamp\" - The interpolation value moves from 0 (after any 'delay') to 1 \n(after a further 'time'), whereby any 'onComplete' callback is fired. The function \n'isComplete()' will return true only after this point. The interpolation stays at 1 after \nthis point.\n* \"repeat\" - The interpolation value moves from 0 (after any 'delay') to 1 (after a further \n'time'), whereby any 'onComplete' callback is fired. The interpolation value then starts \nagain at 0, and moves to 1 after a further 'time'; i.e. it continually cycles with a \nperiod of 'time'. The 'onComplete' callback fires after each period. The function \n'isComplete()' NEVER returns true.\n* \"mirror\" - Like \"repeat\", except that the interpolation value alternately ramps up to 1 \nand back down to 0 for each pair of cycles (as opposed to ramping to 1 and then \nimmediately jumping back to 0). For each odd-numbered cycle, the interpolation value \nis (1-r), where r is the value that would be generated from the corresponding \"repeat\" \nmode. The 'onComplete' callback fires after each period. The function 'isComplete()' \nNEVER returns true.\n* params.easing (function) - The tween easing function. Default value is ease.linear. Easing functions\nallow the properties to be animated in a non-linear fashion, for example to slow down at the start or\nend of the animation period. A full list of easing functions is provided above.\n* params.easingValue (number) - The tween easing value. Depending on the easing function being used,\nthis value can affect the 'strength' of the function, for example the degree to which the animation\nspeeds up or slows down at the start or end of the period. Default value depends on the easing function.\n* params.onStart (function or table) - A function or table listener called before the tween \nbegins. Table listeners must have an 'onStart' method. When invoked, the listener function is\npassed the tween's owning node as an input. The 'onStart' listener is called only once any 'delay'\nperiod has elapsed.\n* params.onComplete (function or table) - A function or table listener called after the \ntween completes. Table listeners must have an 'onComplete' method. When invoked, the listener function is\npassed the tween's owning node as an input. The 'onComplete' listener is called at the end of each\ntween 'cycle': if mode is 'clamp', there is only a single cycle, otherwise cycles repeat indefinitely with\nthe period specified by 'time'.\nExample::\nlocal mySprite = director:createSprite(0, 0, \"textures/beachball.png\")\n-- Animate x and alpha properties, over 1 second, after a delay of 0.5 seconds, with the \"powIn\" easing function\ntween:to(mySprite, { time=1, transition=ease.powIn, delta=0.5, x=100, alpha=0 } )\nDifferent 'modes' can be combined with different easing functions to create standard waves. \nFor example:\n* mode=\"repeat\", easing=ease.linear -- sawtooth wave\n* mode=\"mirror\", easing=ease.linear -- triangle wave\n* mode=\"mirror\", easing=ease.zero -- square wave\nAny target value specified in the tween parameters must exist on the target object. Values can \nbe of type 'number' or 'table'. If of type 'table', the table must include values of type \n'number' and exist on the target object.\nExamples:\n* x=10 (type number)\n* xScale=2 (type number)\n* color={r=0} (type table, containing type number)\n* color={r=0, g=255} (type table, containing type number)\n* uvRect={x=1} (type table, containing type number)",
description = "Tween a series of node properties over time.\nThe final property values are specified in the params table. To customize the\ntween, you can optionally specify the following non-animating properties in params:\n* params.time (number) - The duration of the tween, in seconds. Default value is 0.5. The duration refers\nto the length of a 'cycle'; see the 'mode' parameter below.\n* params.delay (number) - Any delay in seconds before the tween begins. Default value is 0. If this value is\ngreater than 0, then this period must elapse before any properties start tweening. The 'onStart' callback\nis called only when this period has elapsed.\n* params.delta (boolean) - Whether or not to interpret the specified values as absolute, or relative to the\ncurrent values. The default is false, meaning absolute values. If true, the 'current' values are those\nat the point at which any 'delay' period has elapsed.\n* params.mode (string) - Can be 'clamp', 'repeat' or 'mirror'. The default value is 'clamp'.\n* \"clamp\" - The interpolation value moves from 0 (after any 'delay') to 1 \n(after a further 'time'), whereby any 'onComplete' callback is fired. The function \n'isComplete()' will return true only after this point. The interpolation stays at 1 after \nthis point.\n* \"repeat\" - The interpolation value moves from 0 (after any 'delay') to 1 (after a further \n'time'), whereby any 'onComplete' callback is fired. The interpolation value then starts \nagain at 0, and moves to 1 after a further 'time'; i.e. it continually cycles with a \nperiod of 'time'. The 'onComplete' callback fires after each period. The function \n'isComplete()' NEVER returns true.\n* \"mirror\" - Like \"repeat\", except that the interpolation value alternately ramps up to 1 \nand back down to 0 for each pair of cycles (as opposed to ramping to 1 and then \nimmediately jumping back to 0). For each odd-numbered cycle, the interpolation value \nis (1-r), where r is the value that would be generated from the corresponding \"repeat\" \nmode. The 'onComplete' callback fires after each period. The function 'isComplete()' \nNEVER returns true.\n* params.easing (function) - The tween easing function. Default value is ease.linear. Easing functions\nallow the properties to be animated in a non-linear fashion, for example to slow down at the start or\nend of the animation period. A full list of easing functions is provided above.\n* params.easingValue (number) - The tween easing value. Depending on the easing function being used,\nthis value can affect the 'strength' of the function, for example the degree to which the animation\nspeeds up or slows down at the start or end of the period. Default value depends on the easing function.\n* params.onStart (function or table) - A function or table listener called before the tween \nbegins. Table listeners must have an 'onStart' method. When invoked, the listener function is\npassed the tween's owning node as an input. The 'onStart' listener is called only once any 'delay'\nperiod has elapsed.\n* params.onComplete (function or table) - A function or table listener called after the \ntween completes. Table listeners must have an 'onComplete' method. When invoked, the listener function is\npassed the tween's owning node as an input. The 'onComplete' listener is called at the end of each\ntween 'cycle': if mode is 'clamp', there is only a single cycle, otherwise cycles repeat indefinitely with\nthe period specified by 'time'.\nExample::\nlocal mySprite = director:createSprite(0, 0, \"textures/beachball.png\")\n-- Animate x and alpha properties, over 1 second, after a delay of 0.5 seconds, with the \"powIn\" easing function\ntween:to(mySprite, { time=1, easing=ease.powIn, delay=0.5, x=100, alpha=0 } )\nDifferent 'modes' can be combined with different easing functions to create standard waves. \nFor example:\n* mode=\"repeat\", easing=ease.linear -- sawtooth wave\n* mode=\"mirror\", easing=ease.linear -- triangle wave\n* mode=\"mirror\", easing=ease.zero -- square wave\nAny target value specified in the tween parameters must exist on the target object. Values can \nbe of type 'number' or 'table'. If of type 'table', the table must include values of type \n'number' and exist on the target object.\nExamples:\n* x=10 (type number)\n* xScale=2 (type number)\n* color={r=0} (type table, containing type number)\n* color={r=0, g=255} (type table, containing type number)\n* uvRect={x=1} (type table, containing type number)",
args = "(target: object, params: table)",
returns = "(object)",
},

BIN
bin/clibs/git/core.dll Normal file

Binary file not shown.

BIN
bin/clibs/git/core.dylib Normal file

Binary file not shown.

BIN
bin/clibs/lfs.dll Normal file

Binary file not shown.

BIN
bin/clibs/lfs.dylib Normal file

Binary file not shown.

BIN
bin/clibs/liblua.dll Normal file

Binary file not shown.

BIN
bin/clibs/libzlib.dll Normal file

Binary file not shown.

BIN
bin/clibs52/liblua.dll Normal file

Binary file not shown.

Binary file not shown.

BIN
bin/linux/x64/clibs/lfs.so Normal file

Binary file not shown.

Binary file not shown.

BIN
bin/linux/x86/clibs/lfs.so Normal file

Binary file not shown.

View File

@@ -84,6 +84,8 @@ if(WIN32)
install_from_manifest(FILES ${TOPDIR}/zbstudio/MANIFEST ${DATADIR} "^$")
install_from_manifest(FILES ${TOPDIR}/zbstudio/MANIFEST-bin-win32 ${DATADIR} "^zbstudio.exe$")
elseif(APPLE)
set(OSX_INSTALL_PREFIX "/Applications" CACHE PATH "Default OSX prefix")
set(CMAKE_INSTALL_PREFIX "${OSX_INSTALL_PREFIX}" CACHE INTERNAL "Prefix prepended to install directories")
# setup the data directory
set(ROOTDIR ZeroBraneStudio.app/Contents)
set(DATADIR ${ROOTDIR}/ZeroBraneStudio)

View File

@@ -6,6 +6,8 @@ sudo apt-get install git-core
sudo apt-get install g++
sudo apt-get install subversion
sudo apt-get install libgtk2.0-dev
sudo apt-get install cmake
exit
# install cmake as wxwidgets needs 2.8.4+ but "sudo apt-get install cmake"
# only installs 2.8.0 on some systems (like Ubuntu 10.4)

View File

@@ -24,14 +24,6 @@ BUILD_FLAGS="-O2 -shared -s -I $INSTALL_DIR/include -L $INSTALL_DIR/lib $FPIC"
WXWIDGETS_BASENAME="wxWidgets"
WXWIDGETS_URL="http://svn.wxwidgets.org/svn/wx/wxWidgets/trunk"
LIBPNG_BASENAME="libpng-1.6.2"
LIBPNG_FILENAME="$LIBPNG_BASENAME.tar.gz"
LIBPNG_URL="http://sourceforge.net/projects/libpng/files/libpng16/1.6.2/libpng-1.6.2.tar.gz/download"
ZLIB_BASENAME="zlib-1.2.8"
ZLIB_FILENAME="$ZLIB_BASENAME.tar.gz"
ZLIB_URL="https://github.com/madler/zlib/archive/v1.2.8.tar.gz"
WXLUA_BASENAME="wxlua"
WXLUA_URL="https://svn.code.sf.net/p/wxlua/svn/trunk"
@@ -127,35 +119,18 @@ fi
# build wxWidgets
if [ $BUILD_WXWIDGETS ]; then
# first build get/configure libpng as v1.6 is needed
wget -c "$LIBPNG_URL" -O "$LIBPNG_FILENAME" || { echo "Error: failed to download libpng"; exit 1; }
tar -xzf "$LIBPNG_FILENAME"
(cd "$LIBPNG_BASENAME"; ./configure --with-libpng-prefix=wxpng_; make $MAKEFLAGS)
wget -c "$ZLIB_URL" -O "$ZLIB_FILENAME" || { echo "Error: failed to download zlib"; exit 1; }
tar -xzf "$ZLIB_FILENAME"
(cd "$ZLIB_BASENAME"; ./configure; make $MAKEFLAGS)
svn co "$WXWIDGETS_URL" "$WXWIDGETS_BASENAME" || { echo "Error: failed to checkout wxWidgets"; exit 1; }
# replace src/png with the libpng folder
rm -rf "$WXWIDGETS_BASENAME/src/png"
mv "$LIBPNG_BASENAME" "$WXWIDGETS_BASENAME/src/png"
# replace src/zlib with the zlib folder
rm -rf "$WXWIDGETS_BASENAME/src/zlib"
mv "$ZLIB_BASENAME" "$WXWIDGETS_BASENAME/src/zlib"
cd "$WXWIDGETS_BASENAME"
./configure --prefix="$INSTALL_DIR" --disable-debug --disable-shared --enable-unicode \
--enable-compat28 \
--with-libjpeg=builtin --with-libpng=builtin --with-libtiff=no --with-expat=no \
--with-zlib=builtin --disable-richtext --with-gtk=2 \
CFLAGS="-Os -fPIC" CXXFLAGS="-Os -fPIC"
# update gzio to gzlib as this has changed between zlib 1.2.3 to 1.2.8
sed -i 's/gzio.c/gzlib.c/' Makefile
make $MAKEFLAGS || { echo "Error: failed to build wxWidgets"; exit 1; }
make install
cd ..
rm -rf "$WXWIDGETS_BASENAME" "$LIBPNG_FILENAME"
rm -rf "$WXWIDGETS_BASENAME"
fi
# build Lua

View File

@@ -15,7 +15,11 @@ MACOSX_SDK_PATH="/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.pla
MAKEFLAGS="-j4"
# flags for manual building with gcc; build universal binaries for luasocket
MACOSX_FLAGS="-arch $MACOSX_ARCH -mmacosx-version-min=$MACOSX_VERSION -isysroot $MACOSX_SDK_PATH"
MACOSX_FLAGS="-arch $MACOSX_ARCH -mmacosx-version-min=$MACOSX_VERSION"
if [ -d "$MACOSX_SDK_PATH" ]; then
echo "Building with $MACOSX_SDK_PATH"
MACOSX_FLAGS="$MACOSX_FLAGS -isysroot $MACOSX_SDK_PATH"
fi
BUILD_FLAGS="-O2 -arch x86_64 -dynamiclib -undefined dynamic_lookup $MACOSX_FLAGS -I $INSTALL_DIR/include -L $INSTALL_DIR/lib"
# paths configuration
@@ -128,10 +132,15 @@ fi
if [ $BUILD_WXWIDGETS ]; then
svn co "$WXWIDGETS_URL" "$WXWIDGETS_BASENAME" || { echo "Error: failed to checkout wxWidgets"; exit 1; }
cd "$WXWIDGETS_BASENAME"
MINSDK=""
if [ -d $MACOSX_SDK_PATH ]; then
MINSDK="--with-macosx-sdk=$MACOSX_SDK_PATH"
fi
./configure --prefix="$INSTALL_DIR" $WXWIDGETSDEBUG --disable-shared --enable-unicode \
--enable-compat28 \
--with-libjpeg=builtin --with-libpng=builtin --with-libtiff=no --with-expat=no \
--with-zlib=builtin --disable-richtext \
--enable-macosx_arch=$MACOSX_ARCH --with-macosx-version-min=$MACOSX_VERSION --with-macosx-sdk="$MACOSX_SDK_PATH" \
--enable-macosx_arch=$MACOSX_ARCH --with-macosx-version-min=$MACOSX_VERSION $MINSDK \
--with-osx_cocoa CFLAGS="-Os" CXXFLAGS="-Os"
make $MAKEFLAGS || { echo "Error: failed to build wxWidgets"; exit 1; }
make install
@@ -175,11 +184,15 @@ fi
if [ $BUILD_WXLUA ]; then
svn co "$WXLUA_URL" "$WXLUA_BASENAME" || { echo "Error: failed to checkout wxLua"; exit 1; }
cd "$WXLUA_BASENAME/wxLua"
MINSDK=""
if [ -d $MACOSX_SDK_PATH ]; then
MINSDK="CMAKE_OSX_SYSROOT=$MACOSX_SDK_PATH"
fi
# the following patches wxlua source to fix live coding support in wxlua apps
# http://www.mail-archive.com/wxlua-users@lists.sourceforge.net/msg03225.html
sed -i "" 's/\(m_wxlState = wxLuaState(wxlState.GetLuaState(), wxLUASTATE_GETSTATE|wxLUASTATE_ROOTSTATE);\)/\/\/ removed by ZBS build process \/\/ \1/' modules/wxlua/wxlcallb.cpp
cmake -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX="$INSTALL_DIR" -DCMAKE_BUILD_TYPE=$WXLUABUILD -DBUILD_SHARED_LIBS=FALSE \
-DCMAKE_OSX_ARCHITECTURES=$MACOSX_ARCH -DCMAKE_OSX_DEPLOYMENT_TARGET=$MACOSX_VERSION CMAKE_OSX_SYSROOT="$MACOSX_SDK_PATH" \
-DCMAKE_OSX_ARCHITECTURES=$MACOSX_ARCH -DCMAKE_OSX_DEPLOYMENT_TARGET=$MACOSX_VERSION $MINSDK \
-DCMAKE_C_COMPILER=/usr/bin/gcc -DCMAKE_CXX_COMPILER=/usr/bin/g++ -DwxWidgets_CONFIG_EXECUTABLE="$INSTALL_DIR/bin/wx-config" \
-DwxWidgets_COMPONENTS="stc;html;aui;adv;core;net;base" \
-DwxLuaBind_COMPONENTS="stc;html;aui;adv;core;net;base" -DwxLua_LUA_LIBRARY_USE_BUILTIN=FALSE \

View File

@@ -152,6 +152,7 @@ if [ $BUILD_WXWIDGETS ]; then
svn revert -R "$WXWIDGETS_BASENAME"
cd "$WXWIDGETS_BASENAME"
./configure --prefix="$INSTALL_DIR" $WXWIDGETSDEBUG --disable-shared --enable-unicode \
--enable-compat28 \
--with-libjpeg=builtin --with-libpng=builtin --with-libtiff=no --with-expat=no \
--with-zlib=builtin --disable-richtext \
CFLAGS="-Os -fno-keep-inline-dllexport" CXXFLAGS="-Os -fno-keep-inline-dllexport"
@@ -201,8 +202,8 @@ if [ $BUILD_WXLUA ]; then
# (temporary) fix for compilation issue in wxlua in Windows using mingw (r184)
sed -i 's/defined(__MINGW32__) || defined(__GNUWIN32__)/0/' modules/wxbind/src/wxcore_bind.cpp
[ -f "$INSTALL_DIR/lib/libwxscintilla-2.9.a" ] && cp "$INSTALL_DIR/lib/libwxscintilla-2.9.a" "$INSTALL_DIR/lib/libwx_mswu_scintilla-2.9.a"
[ -f "$INSTALL_DIR/lib/libwxscintilla-3.0.a" ] && cp "$INSTALL_DIR/lib/libwxscintilla-3.0.a" "$INSTALL_DIR/lib/libwx_mswu_scintilla-3.0.a"
[ -f "$INSTALL_DIR/lib/libwxscintilla-3.1.a" ] && cp "$INSTALL_DIR/lib/libwxscintilla-3.1.a" "$INSTALL_DIR/lib/libwx_mswu_scintilla-3.1.a"
echo "set_target_properties(wxLuaModule PROPERTIES LINK_FLAGS -static)" >> modules/luamodule/CMakeLists.txt
cmake -G "MSYS Makefiles" -DCMAKE_INSTALL_PREFIX="$INSTALL_DIR" -DCMAKE_BUILD_TYPE=$WXLUABUILD -DBUILD_SHARED_LIBS=FALSE \
@@ -300,6 +301,9 @@ fi
# To build lua5.1.dll proxy:
# (1) get mkforwardlib-gcc.lua from http://lua-users.org/wiki/LuaProxyDllThree
# (2) run it as "lua mkforwardlib-gcc.lua lua51 lua5.1 X86"
# To build lua5.2.dll proxy:
# (1) get mkforwardlib-gcc-52.lua from http://lua-users.org/wiki/LuaProxyDllThree
# (2) run it as "lua mkforwardlib-gcc-52.lua lua52 lua5.2 X86"
echo "*** Build has been successfully completed ***"
exit 0

View File

@@ -9,6 +9,10 @@
-- You can also update an existing file with new messages by running:
-- > bin\lua.exe build/messages.lua cfg/i18n/ru.lua
-- store `print` function as it's modified by wxlua and LuaJIT doesn't like
-- what wxlua has done in that function.
local print = print
local iswindows = os.getenv('WINDIR') or (os.getenv('OS') or ''):match('[Ww]indows')
if iswindows or not pcall(require, "wx") then
package.cpath = (iswindows and 'bin/?.dll;' or 'bin/lib?.dylib;') .. package.cpath

View File

@@ -1,13 +1,17 @@
return {
["%d instance"] = "%d 个体", -- src\editor\findreplace.lua
["%s event failed: %s"] = nil, -- src\editor\package.lua
["&About"] = "关于(&A)", -- src\editor\menu_help.lua
["&Add Watch"] = "添加监视(&A)", -- src\editor\debugger.lua
["&Break"] = "中断", -- src\editor\menu_project.lua
["&Close Page"] = "关闭页面", -- src\editor\menu_file.lua, src\editor\gui.lua
["&Close Page"] = "关闭页面", -- src\editor\gui.lua, src\editor\menu_file.lua
["&Community"] = nil, -- src\editor\menu_help.lua
["&Compile"] = "编译", -- src\editor\menu_project.lua
["&Copy"] = "复制", -- src\editor\editor.lua, src\editor\menu_edit.lua
["&Copy"] = "复制", -- src\editor\menu_edit.lua, src\editor\editor.lua
["&Default Layout"] = "布局", -- src\editor\menu_view.lua
["&Delete Watch"] = "删除监视", -- src\editor\debugger.lua
["&Delete"] = nil, -- src\editor\filetree.lua
["&Documentation"] = nil, -- src\editor\menu_help.lua
["&Down"] = "往下", -- src\editor\findreplace.lua
["&Edit Watch"] = "编辑监视", -- src\editor\debugger.lua
["&Edit"] = "编辑", -- src\editor\menu_edit.lua
@@ -16,47 +20,56 @@ return {
["&Find Next"] = "查找下一个", -- src\editor\findreplace.lua
["&Find"] = "查找", -- src\editor\menu_search.lua
["&Fold/Unfold All"] = "全 折叠/展开", -- src\editor\menu_edit.lua
["&Frequently Asked Questions"] = nil, -- src\editor\menu_help.lua
["&Getting Started Guide"] = nil, -- src\editor\menu_help.lua
["&Goto Line"] = "到...行", -- src\editor\menu_search.lua
["&Help"] = "帮助", -- src\editor\menu_help.lua
["&New Directory"] = nil, -- src\editor\filetree.lua
["&New"] = "新建", -- src\editor\menu_file.lua
["&Open..."] = "打开...", -- src\editor\menu_file.lua
["&Output/Console Window"] = "输出/主控台视窗", -- src\editor\menu_view.lua
["&Paste"] = "粘贴", -- src\editor\editor.lua, src\editor\menu_edit.lua
["&Project"] = "项目", -- src\editor\menu_project.lua, src\editor\inspect.lua
["&Redo"] = "重做", -- src\editor\editor.lua, src\editor\menu_edit.lua
["&Paste"] = "粘贴", -- src\editor\menu_edit.lua, src\editor\editor.lua
["&Project Page"] = nil, -- src\editor\menu_help.lua
["&Project"] = "项目", -- src\editor\inspect.lua, src\editor\menu_project.lua
["&Redo"] = "重做", -- src\editor\menu_edit.lua, src\editor\editor.lua
["&Rename"] = nil, -- src\editor\filetree.lua
["&Replace All"] = "全替换", -- src\editor\findreplace.lua
["&Replace"] = "替换", -- src\editor\findreplace.lua, src\editor\menu_search.lua
["&Run"] = "执行", -- src\editor\menu_project.lua
["&Save"] = "保存", -- src\editor\menu_file.lua, src\editor\gui.lua
["&Save"] = "保存", -- src\editor\gui.lua, src\editor\menu_file.lua
["&Search"] = "搜索", -- src\editor\menu_search.lua
["&Sort"] = "分类", -- src\editor\menu_search.lua
["&Sort"] = "分类", -- src\editor\menu_edit.lua
["&Stack Window"] = "叠视窗/堆栈视窗", -- src\editor\menu_view.lua
["&Start Debugger Server"] = "开启除错器伺服机", -- src\editor\menu_project.lua
["&Subdirectories"] = "子文件夹", -- src\editor\findreplace.lua
["&Undo"] = "撤消", -- src\editor\editor.lua, src\editor\menu_edit.lua
["&Tutorials"] = nil, -- src\editor\menu_help.lua
["&Undo"] = "撤消", -- src\editor\menu_edit.lua, src\editor\editor.lua
["&Up"] = "往上", -- src\editor\findreplace.lua
["&View"] = "视图", -- src\editor\menu_view.lua
["&Watch Window"] = "监视视窗", -- src\editor\menu_view.lua
[".&bak on Replace"] = nil, -- src\editor\findreplace.lua
["About %s"] = "关于 %s", -- src\editor\menu_help.lua
["Add To Scratchpad"] = nil, -- src\editor\editor.lua
["Add Watch Expression"] = "添加监视表达式", -- src\editor\editor.lua
["Add to Scratchpad"] = "添加至暂存器", -- src\editor\editor.lua
["All files"] = "全部文件", -- src\editor\commands.lua
["Allow external process to start debugging"] = "允许外部进程开启除错", -- src\editor\menu_project.lua
["Analyze the source code"] = "分析源代码", -- src\editor\inspect.lua
["Analyze"] = "分析", -- src\editor\inspect.lua
["Auto Complete Identifiers"] = "自动补全标识符", -- src\editor\menu_edit.lua
["Auto complete while typing"] = "当输入时自动补全", -- src\editor\menu_edit.lua
["Break execution at the next executed line of code"] = "执行下一语句之后中断执行", -- src\editor\menu_project.lua, src\editor\gui.lua
["Break execution at the next executed line of code"] = "执行下一语句之后中断执行", -- src\editor\gui.lua, src\editor\menu_project.lua
["C&lear Output Window"] = "清除输出视窗", -- src\editor\menu_project.lua
["C&omment/Uncomment"] = "注释/消除注释", -- src\editor\menu_edit.lua
["Can't debug the script in the active editor window."] = "不能在现行编辑视窗对脚本进行除错", -- src\editor\debugger.lua
["Can't find file '%s' in the current project to activate for debugging. Update the project or open the file in the editor before debugging."] = "在当前项目中寻找不到文件 '%s' 以进行激活然后除错, 更新项目或是在编辑器里开启文件后再除错", -- src\editor\debugger.lua
["Can't process auto-recovery record; invalid format: %s."] = "不能处理自动恢复存档: %s", -- src\editor\commands.lua
["Can't run the entry point script ('%s')."] = "不能执行entry point脚本 ('%s')", -- src\editor\debugger.lua
["Can't start debugger server at %s:%d: %s."] = nil, -- src\editor\debugger.lua
["Can't start debugging session due to internal error '%s'."] = "除错动作失败 '%s'.", -- src\editor\debugger.lua
["Can't start debugging without an opened file or with the current file not being saved ('%s')."] = "不能启动除错,没有文档被开启或当前更改过的文档还没保存('%s')", -- src\editor\debugger.lua
["Cancel"] = "取消", -- src\editor\findreplace.lua
["Choose ..."] = "请选 ...", -- src\editor\menu_project.lua
["Cancelled by the user."] = nil, -- src\editor\findreplace.lua
["Choose..."] = "请选...", -- src\editor\menu_project.lua
["Choose a project directory"] = "选择项目文件夹", -- src\editor\findreplace.lua, src\editor\menu_project.lua
["Clear &Dynamic Words"] = "清除动态词汇", -- src\editor\menu_edit.lua
["Clear the output window before compiling or debugging"] = "编译或除错前清除输出视窗", -- src\editor\menu_project.lua
@@ -65,33 +78,40 @@ return {
["Close the current editor window"] = "关闭当前编译视窗", -- src\editor\menu_file.lua
["Co&ntinue"] = "继续", -- src\editor\menu_project.lua
["Col: %d"] = "列: %d", -- src\editor\editor.lua
["Command Line Parameters..."] = nil, -- src\editor\menu_project.lua
["Command line parameters"] = nil, -- src\editor\menu_project.lua
["Comment or uncomment current or selected lines"] = "注释/消除注释 当前或被选的语句", -- src\editor\menu_edit.lua
["Compilation error"] = "编译错误", -- src\editor\debugger.lua, src\editor\commands.lua
["Compilation error"] = "编译错误", -- src\editor\commands.lua, src\editor\debugger.lua
["Compilation successful; %.0f%% success rate (%d/%d)."] = "编译成功; 成功率: %.0f%% (%d/%d).", -- src\editor\commands.lua
["Compile the current file"] = "编译当前的文档", -- src\editor\menu_project.lua
["Complete &Identifier"] = "补全标识符", -- src\editor\menu_edit.lua
["Complete the current identifier"] = "补全当前标识符", -- src\editor\menu_edit.lua
["Consider removing backslash from escape sequence '%s'."] = nil, -- src\editor\commands.lua
["Copy Full Path"] = nil, -- src\editor\filetree.lua
["Copy selected text to clipboard"] = "复制被选的text到clipboard", -- src\editor\menu_edit.lua
["Couldn't activate file '%s' for debugging; continuing without it."] = "不能激活 '%s' 以除错; 省略后继续进行", -- src\editor\debugger.lua
["Create an empty document"] = "新建空文档", -- src\editor\menu_file.lua, src\editor\gui.lua
["Cu&t"] = "剪切", -- src\editor\editor.lua, src\editor\menu_edit.lua
["Create an empty document"] = "新建空文档", -- src\editor\gui.lua, src\editor\menu_file.lua
["Cu&t"] = "剪切", -- src\editor\menu_edit.lua, src\editor\editor.lua
["Cut selected text to clipboard"] = "剪切被选的text到clipboard", -- src\editor\menu_edit.lua
["Debugger server started at %s:%d."] = "除错伺服器起始于 %s:%d.", -- src\editor\debugger.lua
["Debugging session completed (%s)."] = "除错会话完成 (%s)", -- src\editor\debugger.lua
["Debugging session started in '%s'."] = "除错会话于 '%s' 起始", -- src\editor\debugger.lua
["Debugging suspended at %s:%s (couldn't activate the file)."] = "除错挂起于 %s:%s (不能激活文档).", -- src\editor\debugger.lua
["Directory"] = "文件夹", -- src\editor\findreplace.lua
["Do you want to delete '%s'?"] = nil, -- src\editor\filetree.lua
["Do you want to overwrite it?"] = nil, -- src\editor\commands.lua
["Do you want to reload it?"] = "需要重新导入吗?", -- src\editor\editor.lua
["Do you want to save the changes to '%s'?"] = "需要把更改保存于 '%s'?", -- src\editor\commands.lua
["E&xit"] = "离开", -- src\editor\menu_file.lua
["Enter Lua code and press Enter to run it."] = "输入Lua代码然后按 <Enter> 以执行", -- src\editor\shellbox.lua
["Enter command line parameters (use Cancel to clear)"] = nil, -- src\editor\menu_project.lua
["Enter line number"] = "输入行号码", -- src\editor\menu_search.lua
["Error while loading API file: %s"] = "导入API档时出错误: %s", -- src\editor\autocomplete.lua
["Error while loading configuration file: %s"] = "导入configuration档时出错误: %s", -- src\editor\style.lua
["Error while processing API file: %s"] = "处理API档时出错误: %s", -- src\editor\autocomplete.lua
["Error while processing configuration file: %s"] = "处理configuration档时出错误: %s", -- src\editor\style.lua
["Error"] = "错误", -- src\editor\commands.lua
["Evaluate in Console"] = "在主控台中估值", -- src\editor\editor.lua
["Evaluate In Console"] = nil, -- src\editor\editor.lua
["Execute the current project/file and keep updating the code to see immediate results"] = "执行当前项目/文档和更新代码以便得到执行结果", -- src\editor\menu_project.lua
["Execute the current project/file"] = "执行当前项目/文档", -- src\editor\menu_project.lua
["Execution error"] = "执行出错误", -- src\editor\debugger.lua
@@ -99,19 +119,19 @@ return {
["Expr"] = "表达式", -- src\editor\debugger.lua
["Expression"] = "表达式", -- src\editor\debugger.lua
["File '%s' has been modified on disk."] = "磁碟上的文档 '%s' 已被更改", -- src\editor\editor.lua
["File '%s' has more recent timestamp than restored '%s'; please review before saving."] =
"文档 '%s' 的时间戳比 '%s' 更新近; 请检验后再保存", -- src\editor\commands.lua
["File '%s' no longer exists."] = "文档 '%s' 已不存在", -- src\editor\editor.lua, src\editor\menu_file.lua
["File '%s' has more recent timestamp than restored '%s'; please review before saving."] = "文档 '%s' 的时间戳比 '%s' 更新近; 请检验后再保存", -- src\editor\commands.lua
["File '%s' no longer exists."] = "文档 '%s' 已不存在", -- src\editor\menu_file.lua, src\editor\editor.lua
["File Type"] = "文档类", -- src\editor\findreplace.lua
["File already exists."] = nil, -- src\editor\commands.lua
["File history"] = "文档历史", -- src\editor\menu_file.lua
["Find &In Files"] = "在文档中查找", -- src\editor\menu_search.lua
["Find &Next"] = "查找下一个", -- src\editor\menu_search.lua
["Find &Previous"] = "查找上一个", -- src\editor\menu_search.lua
["Find In Files"] = "在文档中查找", -- src\editor\findreplace.lua
["Find and replace text in files"] = "在文档中查找text然后更换", -- src\editor\menu_search.lua
["Find and replace text"] = "查找text然后更换", -- src\editor\menu_search.lua, src\editor\gui.lua
["Find and replace text"] = "查找text然后更换", -- src\editor\gui.lua, src\editor\menu_search.lua
["Find text in files"] = "在文档中查找text", -- src\editor\menu_search.lua
["Find text"] = "查找text", -- src\editor\menu_search.lua, src\editor\gui.lua
["Find text"] = "查找text", -- src\editor\gui.lua, src\editor\menu_search.lua
["Find the earlier text occurence"] = "查找之前出现的text", -- src\editor\menu_search.lua
["Find the next text occurrence"] = "查找之後将出现的text", -- src\editor\menu_search.lua
["Find"] = "查找", -- src\editor\findreplace.lua
@@ -119,6 +139,7 @@ return {
["Found auto-recovery record and restored saved session."] = "找到自动恢复存档和恢复已存对话", -- src\editor\commands.lua
["Found"] = "找到", -- src\editor\findreplace.lua
["Full &Screen"] = "全屏", -- src\editor\menu_view.lua
["Go To Definition"] = nil, -- src\editor\editor.lua
["Go to a selected line"] = "到所选的行", -- src\editor\menu_search.lua
["Goto Line"] = "到...行", -- src\editor\menu_search.lua
["INS"] = "INS", -- src\editor\editor.lua
@@ -126,18 +147,20 @@ return {
["Jump to a function definition..."] = "跳到函数定义", -- src\editor\editor.lua
["Known Files"] = "所知的文档", -- src\editor\commands.lua
["Ln: %d"] = "行: %d", -- src\editor\editor.lua
["Local console"] = "本地主控台", -- src\editor\shellbox.lua, src\editor\gui.lua
["Local console"] = "本地主控台", -- src\editor\gui.lua, src\editor\shellbox.lua
["Lua &Interpreter"] = "Lua 解释器", -- src\editor\menu_project.lua
["Mapped remote request for '%s' to '%s'."] = "映射远程请求 '%s' 至 '%s'", -- src\editor\debugger.lua
["Match &case"] = "case匹配", -- src\editor\findreplace.lua
["Match &whole word"] = "全句匹配", -- src\editor\findreplace.lua
["Mixed end-of-line encodings detected."] = "发现混杂的EOL编码", -- src\editor\commands.lua
["New &File"] = nil, -- src\editor\filetree.lua
["OVR"] = "OVR", -- src\editor\editor.lua
["Open an existing document"] = "打开现存文档", -- src\editor\menu_file.lua, src\editor\gui.lua
["Open With Default Program"] = nil, -- src\editor\filetree.lua
["Open an existing document"] = "打开现存文档", -- src\editor\gui.lua, src\editor\menu_file.lua
["Open file"] = "打开文档", -- src\editor\commands.lua
["Options"] = "选项", -- src\editor\findreplace.lua
["Output (running)"] = "输出 (进行中)", -- src\editor\output.lua
["Output"] = "输出", -- src\editor\output.lua, src\editor\settings.lua, src\editor\gui.lua
["Output"] = "输出", -- src\editor\gui.lua, src\editor\output.lua, src\editor\settings.lua
["Paste text from the clipboard"] = "从clipboard粘贴text", -- src\editor\menu_edit.lua
["Preferences"] = "首选项", -- src\editor\menu_edit.lua
["Prepend '=' to show complex values on multiple lines."] = "在多行展现复杂值请前置 '='", -- src\editor\shellbox.lua
@@ -149,8 +172,9 @@ return {
["Program stopped (pid: %d)."] = "程式停止 (pid: %d).", -- src\editor\debugger.lua
["Program unable to run as '%s'."] = "程式不能以 '%s' 执行", -- src\editor\output.lua
["Project Directory"] = "项目文件夹", -- src\editor\menu_project.lua
["Project"] = "项目", -- src\editor\settings.lua, src\editor\gui.lua
["Project"] = "项目", -- src\editor\gui.lua, src\editor\settings.lua
["Project/&FileTree Window"] = "项目/文档树 视窗", -- src\editor\menu_view.lua
["Provide command line parameters"] = nil, -- src\editor\menu_project.lua
["R/O"] = "唯读", -- src\editor\editor.lua
["R/W"] = "读写", -- src\editor\editor.lua
["Re&place In Files"] = "在文档中替换", -- src\editor\menu_search.lua
@@ -159,7 +183,8 @@ return {
["Refused a request to start a new debugging session as there is one in progress already."] = "因为有另一个除错在进行,拒绝开启新的除错对话", -- src\editor\debugger.lua
["Regular &expression"] = "正则表达式", -- src\editor\findreplace.lua
["Remote console"] = "远程主控台", -- src\editor\shellbox.lua
["Replace &All"] = "更换全部", -- src\editor\findreplace.lua
["Rename All Instances"] = nil, -- src\editor\editor.lua
["Replace A&ll"] = "更换全部", -- src\editor\findreplace.lua
["Replace"] = "更换", -- src\editor\findreplace.lua
["Replaced an invalid UTF8 character with %s."] = "以%s更换无效的UTF8字元", -- src\editor\commands.lua
["Replaced"] = "更换", -- src\editor\findreplace.lua
@@ -169,47 +194,56 @@ return {
["Run as Scratchpad"] = "以Scratchpad执行", -- src\editor\menu_project.lua
["S&top Debugging"] = "停止除错", -- src\editor\menu_project.lua
["S&top Process"] = "停止进程", -- src\editor\menu_project.lua
["Save &As..."] = "另存为...", -- src\editor\menu_file.lua, src\editor\gui.lua
["Save &As..."] = "另存为...", -- src\editor\gui.lua, src\editor\menu_file.lua
["Save A&ll"] = "全部存档", -- src\editor\menu_file.lua
["Save Changes?"] = "存档更新?", -- src\editor\commands.lua
["Save all open documents"] = "保存所有开启的文档", -- src\editor\menu_file.lua, src\editor\gui.lua
["Save all open documents"] = "保存所有开启的文档", -- src\editor\gui.lua, src\editor\menu_file.lua
["Save file as"] = "文档另存为", -- src\editor\commands.lua
["Save file?"] = "保存文档?", -- src\editor\commands.lua
["Save the current document to a file with a new name"] = "用新档案名称保存当前文档", -- src\editor\menu_file.lua
["Save the current document"] = "保存当前文档", -- src\editor\menu_file.lua, src\editor\gui.lua
["Save the current document"] = "保存当前文档", -- src\editor\gui.lua, src\editor\menu_file.lua
["Saved auto-recover at %s."] = "在 %s 存档自动恢复", -- src\editor\commands.lua
["Scope"] = "范围", -- src\editor\findreplace.lua
["Scratchpad error"] = "暂存器错误", -- src\editor\debugger.lua
["Searching for"] = "搜索", -- src\editor\findreplace.lua
["Select &All"] = "选全部", -- src\editor\editor.lua, src\editor\menu_edit.lua
["Select &All"] = "选全部", -- src\editor\menu_edit.lua, src\editor\editor.lua
["Select all text in the editor"] = "选编辑器内的所有text", -- src\editor\menu_edit.lua
["Select and Find Next"] = nil, -- src\editor\menu_search.lua
["Select and Find Previous"] = nil, -- src\editor\menu_search.lua
["Select the word under cursor and find its next occurrence"] = nil, -- src\editor\menu_search.lua
["Select the word under cursor and find its previous occurrence"] = nil, -- src\editor\menu_search.lua
["Set From Current File"] = "从当前文档设置", -- src\editor\menu_project.lua
["Set project directory from current file"] = "从当前文档设置项目文件夹", -- src\editor\menu_project.lua, src\editor\gui.lua
["Set project directory from current file"] = "从当前文档设置项目文件夹", -- src\editor\gui.lua, src\editor\menu_project.lua
["Set the interpreter to be used"] = "设置解释器", -- src\editor\menu_project.lua
["Set the project directory to be used"] = "设置项目文件夹", -- src\editor\menu_project.lua
["Settings: System"] = "设置: 系统", -- src\editor\menu_edit.lua
["Settings: User"] = "设置: 用户", -- src\editor\menu_edit.lua
["Show &Tooltip"] = "展现tooltip", -- src\editor\menu_edit.lua
["Show Location"] = nil, -- src\editor\gui.lua, src\editor\filetree.lua
["Show tooltip for current position; place cursor after opening bracket of function"] = "在当前的位置展现tooltip; 把游标放置于函数的开括号之后", -- src\editor\menu_edit.lua
["Sort selected lines"] = "对被选的行进行排列", -- src\editor\menu_search.lua
["Stack"] = "堆栈", -- src\editor\debugger.lua
["Sort selected lines"] = "对被选的行进行排列", -- src\editor\menu_edit.lua
["Stack"] = "堆栈", -- src\editor\debugger.lua, src\editor\gui.lua
["Start &Debugging"] = "开始除错", -- src\editor\menu_project.lua
["Start debugging"] = "开始除错", -- src\editor\menu_project.lua, src\editor\gui.lua
["Start or Continue debugging"] = nil, -- src\editor\gui.lua
["Start or continue debugging"] = nil, -- src\editor\menu_project.lua
["Step &Into"] = "除错运行 进入子程序/函数", -- src\editor\menu_project.lua
["Step &Over"] = "除错运行 掠过子程序/函数", -- src\editor\menu_project.lua
["Step O&ut"] = "除错运行 离开子程序/函数", -- src\editor\menu_project.lua
["Step into"] = "除错运行 进入子程序/函数", -- src\editor\menu_project.lua, src\editor\gui.lua
["Step out of the current function"] = "除错运行 离开当前的函数", -- src\editor\menu_project.lua, src\editor\gui.lua
["Step over"] = "除错运行 掠过子程序/函数", -- src\editor\menu_project.lua, src\editor\gui.lua
["Stop the currently running process"] = "终止目前进行着的进程", -- src\editor\menu_project.lua, src\editor\gui.lua
["Step into"] = "除错运行 进入子程序/函数", -- src\editor\gui.lua, src\editor\menu_project.lua
["Step out of the current function"] = "除错运行 离开当前的函数", -- src\editor\gui.lua, src\editor\menu_project.lua
["Step over"] = "除错运行 掠过子程序/函数", -- src\editor\gui.lua, src\editor\menu_project.lua
["Stop the currently running process"] = "终止目前进行着的进程", -- src\editor\gui.lua, src\editor\menu_project.lua
["Switch to or from full screen mode"] = "切换全屏模式", -- src\editor\menu_view.lua
["Text not found."] = "寻找不到text", -- src\editor\findreplace.lua
["The API file must be located in a subdirectory of the API directory."] = "API file必须存放在API文件夹中的子文件夹", -- src\editor\autocomplete.lua
["Toggle Break&point"] = "切换中断点", -- src\editor\menu_project.lua
["Toggle breakpoint"] = "切换中断点", -- src\editor\menu_project.lua, src\editor\gui.lua
["Toggle breakpoint"] = "切换中断点", -- src\editor\gui.lua, src\editor\menu_project.lua
["Tr&ace"] = "追踪", -- src\editor\menu_project.lua
["Trace execution showing each executed line"] = "执行追踪展示每一执行过的语句", -- src\editor\menu_project.lua
["Unable to create directory '%s'."] = nil, -- src\editor\filetree.lua
["Unable to create file '%s'."] = nil, -- src\editor\filetree.lua
["Unable to load file '%s'."] = "导出文件失败 '%s'.", -- src\editor\commands.lua
["Unable to rename file '%s'."] = nil, -- src\editor\filetree.lua
["Unable to save file '%s': %s"] = "保存文件失败 '%s': %s", -- src\editor\commands.lua
["Unable to stop program (pid: %d), code %d."] = "停止程序失败 (pid: %d), 代码 %d.", -- src\editor\debugger.lua
["Undo last edit"] = "清除前编辑动作", -- src\editor\menu_edit.lua
@@ -220,12 +254,13 @@ return {
["Value"] = "数值", -- src\editor\debugger.lua
["View the output/console window"] = "查看输出/主控台视窗", -- src\editor\menu_view.lua
["View the project/filetree window"] = "查看项目/文件树视窗", -- src\editor\menu_view.lua
["View the stack window"] = "查看堆栈视窗", -- src\editor\menu_view.lua, src\editor\gui.lua
["View the watch window"] = "查看监视视窗", -- src\editor\menu_view.lua, src\editor\gui.lua
["Watch"] = "监视", -- src\editor\debugger.lua
["View the stack window"] = "查看堆栈视窗", -- src\editor\gui.lua, src\editor\menu_view.lua
["View the watch window"] = "查看监视视窗", -- src\editor\gui.lua, src\editor\menu_view.lua
["Watch"] = "监视", -- src\editor\debugger.lua, src\editor\gui.lua
["Welcome to the interactive Lua interpreter."] = "欢迎来到互动 Lua interpreter.", -- src\editor\shellbox.lua
["Wrap ar&ound"] = "卷绕", -- src\editor\findreplace.lua
["You must save the program first."] = "必须先保存程序", -- src\editor\commands.lua
["on line %d"] = "在 %d 行", -- src\editor\debugger.lua, src\editor\commands.lua
["on line %d"] = "在 %d 行", -- src\editor\debugger.lua, src\editor\editor.lua, src\editor\commands.lua
["traced %d instruction"] = "追踪 %d 指令", -- src\editor\debugger.lua
["unknown error"] = nil, -- src\editor\debugger.lua
}

View File

@@ -5,11 +5,14 @@ return {
["&About"] = "&Über", -- src\editor\menu_help.lua
["&Add Watch"] = "&Beobachtungspunkt hinzufügen", -- src\editor\debugger.lua
["&Break"] = "&Unterbrechung", -- src\editor\menu_project.lua
["&Close Page"] = "S&eite schließen", -- src\editor\menu_file.lua, src\editor\gui.lua
["&Close Page"] = "S&eite schließen", -- src\editor\gui.lua, src\editor\menu_file.lua
["&Community"] = "&Community", -- src\editor\menu_help.lua
["&Compile"] = "&Compiler", -- src\editor\menu_project.lua
["&Copy"] = "&Kopieren", -- src\editor\editor.lua, src\editor\menu_edit.lua
["&Copy"] = "&Kopieren", -- src\editor\menu_edit.lua, src\editor\editor.lua
["&Default Layout"] = "Standard-&Layout", -- src\editor\menu_view.lua
["&Delete Watch"] = "&Beobachtungspunkt entfernen", -- src\editor\debugger.lua
["&Delete"] = "&Entfernen", -- src\editor\filetree.lua
["&Documentation"] = "&Dokumentation", -- src\editor\menu_help.lua
["&Down"] = "&Runter", -- src\editor\findreplace.lua
["&Edit Watch"] = "&Beobachtungspunkt bearbeiten", -- src\editor\debugger.lua
["&Edit"] = "&Bearbeiten", -- src\editor\menu_edit.lua
@@ -18,48 +21,56 @@ return {
["&Find Next"] = "&Nächsten finden", -- src\editor\findreplace.lua
["&Find"] = "&Finden", -- src\editor\menu_search.lua
["&Fold/Unfold All"] = "A&lles ein-/ausklappen", -- src\editor\menu_edit.lua
["&Frequently Asked Questions"] = "&FAQ", -- src\editor\menu_help.lua
["&Getting Started Guide"] = "&Anfängerleitfaden", -- src\editor\menu_help.lua
["&Goto Line"] = "&Gehe zu Zeile", -- src\editor\menu_search.lua
["&Help"] = "&Hilfe", -- src\editor\menu_help.lua
["&New Directory"] = "&Neuer Ordner", -- src\editor\filetree.lua
["&New"] = "&Neu", -- src\editor\menu_file.lua
["&Open..."] = "&Öffnen...", -- src\editor\menu_file.lua
["&Output/Console Window"] = "&Ausgabefenster/Konsole", -- src\editor\menu_view.lua
["&Paste"] = "&Einfügen", -- src\editor\editor.lua, src\editor\menu_edit.lua
["&Project"] = "&Projekt", -- src\editor\menu_project.lua, src\editor\inspect.lua
["&Redo"] = "&Wiederholen", -- src\editor\editor.lua, src\editor\menu_edit.lua
["&Paste"] = "&Einfügen", -- src\editor\menu_edit.lua, src\editor\editor.lua
["&Project Page"] = "&Projektseite", -- src\editor\menu_help.lua
["&Project"] = "&Projekt", -- src\editor\inspect.lua, src\editor\menu_project.lua
["&Redo"] = "&Wiederholen", -- src\editor\menu_edit.lua, src\editor\editor.lua
["&Rename"] = "&Umbenennen", -- src\editor\filetree.lua
["&Replace All"] = "&Alles ersetzen", -- src\editor\findreplace.lua
["&Replace"] = "&Ersetzen", -- src\editor\findreplace.lua, src\editor\menu_search.lua
["&Run"] = "&Starten", -- src\editor\menu_project.lua
["&Save"] = "&Speichern", -- src\editor\menu_file.lua, src\editor\gui.lua
["&Save"] = "&Speichern", -- src\editor\gui.lua, src\editor\menu_file.lua
["&Search"] = "&Suchen", -- src\editor\menu_search.lua
["&Sort"] = "&Sortieren", -- src\editor\menu_search.lua
["&Sort"] = "&Sortieren", -- src\editor\menu_edit.lua
["&Stack Window"] = "&Stapel/Stack", -- src\editor\menu_view.lua
["&Start Debugger Server"] = "De&bugserver starten", -- src\editor\menu_project.lua
["&Subdirectories"] = "&Unterverzeichnisse", -- src\editor\findreplace.lua
["&Undo"] = "&Rückgängig", -- src\editor\editor.lua, src\editor\menu_edit.lua
["&Tutorials"] = "&Tutorien", -- src\editor\menu_help.lua
["&Undo"] = "&Rückgängig", -- src\editor\menu_edit.lua, src\editor\editor.lua
["&Up"] = "&Hoch", -- src\editor\findreplace.lua
["&View"] = "&Ansicht", -- src\editor\menu_view.lua
["&Watch Window"] = "&Beobachtungspunkte", -- src\editor\menu_view.lua
[".&bak on Replace"] = ".&bak bei Ersetzen", -- src\editor\findreplace.lua
["About %s"] = "Über %s", -- src\editor\menu_help.lua
["Add Watch Expression"] = "Beobachtungspunkt hinzufügen", -- src\editor\editor.lua
["Add To Scratchpad"] = "Zu Entwurf hinzufügen", -- src\editor\editor.lua
["Add Watch Expression"] = "Beobachtungspunkt hinzufügen", -- src\editor\editor.lua
["All files"] = "Alle Dateien", -- src\editor\commands.lua
["Allow external process to start debugging"] = "Externem Prozeß erlauben, den Debugger zu starten", -- src\editor\menu_project.lua
["Analyze the source code"] = "Quellcode analysieren", -- src\editor\inspect.lua
["Analyze"] = "&Analyseroutine", -- src\editor\inspect.lua
["Auto Complete Identifiers"] = "Auto-Vervollständigen von Bezeichnern", -- src\editor\menu_edit.lua
["Auto complete while typing"] = "Auto-Vervollständigen beim Tippen", -- src\editor\menu_edit.lua
["Break execution at the next executed line of code"] = "Programmausführung bei der nächsten ausgeführten Zeile stoppen", -- src\editor\menu_project.lua, src\editor\gui.lua
["C&lear Output Window"] = "Ausgabefenster &löschen", -- src\editor\menu_project.lua
["C&omment/Uncomment"] = "(Aus-)/&Kommentieren", -- src\editor\menu_edit.lua
["Break execution at the next executed line of code"] = "Programmausführung bei der nächsten ausgeführten Zeile stoppen", -- src\editor\gui.lua, src\editor\menu_project.lua
["C&lear Output Window"] = "Ausgabefenster l&öschen", -- src\editor\menu_project.lua
["C&omment/Uncomment"] = "(Aus-)/K&ommentieren", -- src\editor\menu_edit.lua
["Can't debug the script in the active editor window."] = "Script kann im aktiven Editorfenster nicht gedebuggt werden.", -- src\editor\debugger.lua
["Can't find file '%s' in the current project to activate for debugging. Update the project or open the file in the editor before debugging."] = "Kann Datei '%s' zwecks Debugging im aktuellen Projekt nicht finden. Bitte Projekt aktualisieren oder Datei in den Editor laden.", -- src\editor\debugger.lua
["Can't process auto-recovery record; invalid format: %s."] = "Auto-Wiederherstellen nicht möglich; ungültiges Format: %s.", -- src\editor\commands.lua
["Can't run the entry point script ('%s')."] = "Kann Script für Einsprungspunkt ('%s') nicht ausführen.", -- src\editor\debugger.lua
["Can't start debugger server at %s:%d: %s."] = "Kann Debugserver nicht starten (%s:%d): %s.", -- src\editor\debugger.lua
["Can't start debugging session due to internal error '%s'."] = "Debugging kann nicht gestartet werden wegen internem Fehler '%s'.", -- src\editor\debugger.lua
["Can't start debugging without an opened file or with the current file not being saved ('%s')."] = "Debugging kann nicht gestartet werden ohne geöffnete Datei oder wenn die aktuelle Datei nicht gespeichert ist ('%s').", -- src\editor\debugger.lua
["Can't start debugging without an opened file or with the current file not being saved ('%s')."] = "Debugging kann ohne geöffnete Datei nicht gestartet werden oder wenn die aktuelle Datei nicht gespeichert ist ('%s').", -- src\editor\debugger.lua
["Cancel"] = "Abbrechen", -- src\editor\findreplace.lua
["Choose ..."] = "Wählen...", -- src\editor\menu_project.lua
["Cancelled by the user."] = "Durch Benutzer abgebrochen.", -- src\editor\findreplace.lua
["Choose..."] = "Wählen...", -- src\editor\menu_project.lua
["Choose a project directory"] = "Projektverzeichnis auswählen", -- src\editor\findreplace.lua, src\editor\menu_project.lua
["Clear &Dynamic Words"] = "&Dynamic Words löschen", -- src\editor\menu_edit.lua
["Clear the output window before compiling or debugging"] = "Vor Kompilieren oder Debuggen das Ausgabefenster löschen", -- src\editor\menu_project.lua
@@ -68,26 +79,33 @@ return {
["Close the current editor window"] = "Aktuelles Editorfenster schließen", -- src\editor\menu_file.lua
["Co&ntinue"] = "&Fortsetzen", -- src\editor\menu_project.lua
["Col: %d"] = "Spalte: %d", -- src\editor\editor.lua
["Command Line Parameters..."] = "Kommandozeilenparameter...", -- src\editor\menu_project.lua
["Command line parameters"] = "Kommandozeilenparameter", -- src\editor\menu_project.lua
["Comment or uncomment current or selected lines"] = "Ausgewählte bzw. aktive Zeile (un-)kommentieren", -- src\editor\menu_edit.lua
["Compilation error"] = "Fehler beim Kompilieren", -- src\editor\debugger.lua, src\editor\commands.lua
["Compilation error"] = "Fehler beim Kompilieren", -- src\editor\commands.lua, src\editor\debugger.lua
["Compilation successful; %.0f%% success rate (%d/%d)."] = "Kompilieren erfolgreich; Erfolgsquote von %.0f%% (%d/%d).", -- src\editor\commands.lua
["Compile the current file"] = "Aktuelle Datei kompilieren", -- src\editor\menu_project.lua
["Complete &Identifier"] = "&Bezeichner vervollständigen", -- src\editor\menu_edit.lua
["Complete the current identifier"] = " Aktuellen Bezeichner vervollständigen", -- src\editor\menu_edit.lua
["Consider removing backslash from escape sequence '%s'."] = "Möglicherweise muß `\' aus '%s' entfernt werden.", -- src\editor\commands.lua
["Copy Full Path"] = "Kopiere Pfadangabe", -- src\editor\filetree.lua
["Copy selected text to clipboard"] = "Text in Zwischenablage kopieren", -- src\editor\menu_edit.lua
["Couldn't activate file '%s' for debugging; continuing without it."] = "Konnte Datei '%s' zwecks nicht Debugging aktivieren; fahre ohne die Datei fort.", -- src\editor\debugger.lua
["Create an empty document"] = "Leeres Dokument anlegen", -- src\editor\menu_file.lua, src\editor\gui.lua
["Cu&t"] = "A&usschneiden", -- src\editor\editor.lua, src\editor\menu_edit.lua
["Create an empty document"] = "Leeres Dokument anlegen", -- src\editor\gui.lua, src\editor\menu_file.lua
["Cu&t"] = "A&usschneiden", -- src\editor\menu_edit.lua, src\editor\editor.lua
["Cut selected text to clipboard"] = "Schneide ausgewählten Text in die Zwischenablage hinein", -- src\editor\menu_edit.lua
["Debugger server started at %s:%d."] = "Debugserver gestartet an %s:%d.", -- src\editor\debugger.lua
["Debugger server started at %s:%d."] = "Debugserver gestartet als %s:%d.", -- src\editor\debugger.lua
["Debugging session completed (%s)."] = "Debugging Session beendet (%s).", -- src\editor\debugger.lua
["Debugging session started in '%s'."] = "Debugging Session gestartet '%s'.", -- src\editor\debugger.lua
["Debugging suspended at %s:%s (couldn't activate the file)."] = "Debugging angehalten bei %s:%s (konnte Datei nicht aktivieren).", -- src\editor\debugger.lua
["Directory"] = "Verzeichnis", -- src\editor\findreplace.lua
["Do you want to delete '%s'?"] = "Soll '%s' gelöscht werden?", -- src\editor\filetree.lua
["Do you want to overwrite it?"] = "Überschreiben?", -- src\editor\commands.lua
["Do you want to reload it?"] = "Neu laden?", -- src\editor\editor.lua
["Do you want to save the changes to '%s'?"] = "Änderungen an '%s' speichern?", -- src\editor\commands.lua
["E&xit"] = "&Beenden", -- src\editor\menu_file.lua
["Enter Lua code and press Enter to run it."] = "Lua-Code eingeben und Enter drücken zum Ausführen.", -- src\editor\shellbox.lua
["Enter command line parameters (use Cancel to clear)"] = "Kommandozeilenparameter eingeben (Cancel zum löschen)", -- src\editor\menu_project.lua
["Enter line number"] = "Zeilennummer eingeben", -- src\editor\menu_search.lua
["Error while loading API file: %s"] = "Fehler beim Laden von API-Datei: %s", -- src\editor\autocomplete.lua
["Error while loading configuration file: %s"] = "Fehler beim Laden von Konfigurationsdatei: %s", -- src\editor\style.lua
@@ -103,17 +121,18 @@ return {
["Expression"] = "Ausdruck", -- src\editor\debugger.lua
["File '%s' has been modified on disk."] = "Datei '%s' wurde auf der Festplatte geändert.", -- src\editor\editor.lua
["File '%s' has more recent timestamp than restored '%s'; please review before saving."] = "Datei '%s' hat neueren Zeitstempel als wiederhergestellte Datei '%s'; bitte vor dem Speichern kontrollieren.", -- src\editor\commands.lua
["File '%s' no longer exists."] = "Datei '%s' existiert nicht mehr.", -- src\editor\editor.lua, src\editor\menu_file.lua
["File '%s' no longer exists."] = "Datei '%s' existiert nicht mehr.", -- src\editor\menu_file.lua, src\editor\editor.lua
["File Type"] = "Dateityp", -- src\editor\findreplace.lua
["File already exists."] = "Datei existiert bereits.", -- src\editor\commands.lua
["File history"] = "Dateiverlauf", -- src\editor\menu_file.lua
["Find &In Files"] = "Finde &in Dateien", -- src\editor\menu_search.lua
["Find &Next"] = "Finde &Nächste", -- src\editor\menu_search.lua
["Find &Previous"] = "Finde &Vorherige", -- src\editor\menu_search.lua
["Find In Files"] = "Finde in Dateien", -- src\editor\findreplace.lua
["Find and replace text in files"] = "Finde und ersetze Text in Dateien", -- src\editor\menu_search.lua
["Find and replace text"] = "Finde und ersetze Text", -- src\editor\menu_search.lua, src\editor\gui.lua
["Find and replace text"] = "Finde und ersetze Text", -- src\editor\gui.lua, src\editor\menu_search.lua
["Find text in files"] = "Finde Text in Dateien", -- src\editor\menu_search.lua
["Find text"] = "Finde Text", -- src\editor\menu_search.lua, src\editor\gui.lua
["Find text"] = "Finde Text", -- src\editor\gui.lua, src\editor\menu_search.lua
["Find the earlier text occurence"] = "Finde vorheriges Auftreten des Textes", -- src\editor\menu_search.lua
["Find the next text occurrence"] = "Finde nächstes Auftreten des Textes", -- src\editor\menu_search.lua
["Find"] = "Finden", -- src\editor\findreplace.lua
@@ -129,18 +148,20 @@ return {
["Jump to a function definition..."] = "Springe zu Funktions-Definition...", -- src\editor\editor.lua
["Known Files"] = "Bekannte Dateien", -- src\editor\commands.lua
["Ln: %d"] = "Zeile: %d", -- src\editor\editor.lua
["Local console"] = "Lokale Konsole", -- src\editor\shellbox.lua, src\editor\gui.lua
["Local console"] = "Lokale Konsole", -- src\editor\gui.lua, src\editor\shellbox.lua
["Lua &Interpreter"] = "&Lua Interpreter", -- src\editor\menu_project.lua
["Mapped remote request for '%s' to '%s'."] = "Mapped remote request for '%s' to '%s'.", -- src\editor\debugger.lua
["Match &case"] = "&Groß-/Kleinschreibung", -- src\editor\findreplace.lua
["Match &whole word"] = "Ganzes &Wort", -- src\editor\findreplace.lua
["Mixed end-of-line encodings detected."] = "Gemischte End-of-Line Kodierung entdeckt.", -- src\editor\commands.lua
["New &File"] = "Neue &Datei", -- src\editor\filetree.lua
["OVR"] = "OVR", -- src\editor\editor.lua
["Open an existing document"] = "Öffne existierendes Dokument", -- src\editor\menu_file.lua, src\editor\gui.lua
["Open With Default Program"] = "Mit Standardanwendung öffnen", -- src\editor\filetree.lua
["Open an existing document"] = "Öffne existierendes Dokument", -- src\editor\gui.lua, src\editor\menu_file.lua
["Open file"] = "Öffne Datei", -- src\editor\commands.lua
["Options"] = "Optionen", -- src\editor\findreplace.lua
["Output (running)"] = "Ausgabe (ausgeführt)", -- src\editor\output.lua
["Output"] = "Ausgabe", -- src\editor\output.lua, src\editor\settings.lua, src\editor\gui.lua
["Output"] = "Ausgabe", -- src\editor\gui.lua, src\editor\output.lua, src\editor\settings.lua
["Paste text from the clipboard"] = "Text aus Zwischenablage einfügen", -- src\editor\menu_edit.lua
["Preferences"] = "Einstellungen", -- src\editor\menu_edit.lua
["Prepend '=' to show complex values on multiple lines."] = "'=' voranstellen, um komplexe Ausdrücke auf mehrere Zeilen zu verteilen.", -- src\editor\shellbox.lua
@@ -152,8 +173,9 @@ return {
["Program stopped (pid: %d)."] = "Programm gestoppt (pid: %d).", -- src\editor\debugger.lua
["Program unable to run as '%s'."] = "Programm kann nicht als '%s' laufen.", -- src\editor\output.lua
["Project Directory"] = "&Projektverzeichnis", -- src\editor\menu_project.lua
["Project"] = "Projekt", -- src\editor\settings.lua, src\editor\gui.lua
["Project"] = "Projekt", -- src\editor\gui.lua, src\editor\settings.lua
["Project/&FileTree Window"] = "&Projekt/Datei Fenster", -- src\editor\menu_view.lua
["Provide command line parameters"] = "Kommandozeilenparameter angeben", -- src\editor\menu_project.lua
["R/O"] = "R/O", -- src\editor\editor.lua
["R/W"] = "R/W", -- src\editor\editor.lua
["Re&place In Files"] = "Ersetze in &Dateien", -- src\editor\menu_search.lua
@@ -163,7 +185,7 @@ return {
["Regular &expression"] = "&Regulärer Ausdruck", -- src\editor\findreplace.lua
["Remote console"] = "Fensteuerungs-Konsole", -- src\editor\shellbox.lua
["Rename All Instances"] = "Umbenennen aller Instanzen", -- src\editor\editor.lua
["Replace &All"] = "&Alles ersetzen", -- src\editor\findreplace.lua
["Replace A&ll"] = "A&lles ersetzen", -- src\editor\findreplace.lua
["Replace"] = "Ersetzen", -- src\editor\findreplace.lua
["Replaced an invalid UTF8 character with %s."] = "Unbekanntes UTF8-Symbol ersetzt mit %s.", -- src\editor\commands.lua
["Replaced"] = "Ersetzt:", -- src\editor\findreplace.lua
@@ -173,22 +195,26 @@ return {
["Run as Scratchpad"] = "Als &Entwurf starten", -- src\editor\menu_project.lua
["S&top Debugging"] = "Debugging a&nhalten", -- src\editor\menu_project.lua
["S&top Process"] = "Prozeß &anhalten", -- src\editor\menu_project.lua
["Save &As..."] = "S&peichern als...", -- src\editor\menu_file.lua, src\editor\gui.lua
["Save &As..."] = "S&peichern als...", -- src\editor\gui.lua, src\editor\menu_file.lua
["Save A&ll"] = "&Alle Speichern", -- src\editor\menu_file.lua
["Save Changes?"] = "Änderungen speichern?", -- src\editor\commands.lua
["Save all open documents"] = "Alle offenen Dokumente speichern", -- src\editor\menu_file.lua, src\editor\gui.lua
["Save all open documents"] = "Alle offenen Dokumente speichern", -- src\editor\gui.lua, src\editor\menu_file.lua
["Save file as"] = "Datei speichern als", -- src\editor\commands.lua
["Save file?"] = "Datei speichern?", -- src\editor\commands.lua
["Save the current document to a file with a new name"] = "Aktuelles Dokument unter neuem Namen speichern", -- src\editor\menu_file.lua
["Save the current document"] = "Aktuelles Dokument speichern", -- src\editor\menu_file.lua, src\editor\gui.lua
["Saved auto-recover at %s."] = "Autowiederherstellen gespeichert unter %s.", -- src\editor\commands.lua
["Save the current document"] = "Aktuelles Dokument speichern", -- src\editor\gui.lua, src\editor\menu_file.lua
["Saved auto-recover at %s."] = "%s Autowiederherstellen gespeichert.", -- src\editor\commands.lua
["Scope"] = "Richtung", -- src\editor\findreplace.lua
["Scratchpad error"] = "Fehler im Entwurf", -- src\editor\debugger.lua
["Searching for"] = "Suchen nach", -- src\editor\findreplace.lua
["Select &All"] = "&Alles Auswählen", -- src\editor\editor.lua, src\editor\menu_edit.lua
["Select &All"] = "&Alles Auswählen", -- src\editor\menu_edit.lua, src\editor\editor.lua
["Select all text in the editor"] = "Kompletten Text im Editor auswählen", -- src\editor\menu_edit.lua
["Select and Find Next"] = "Auswählen und nächstes finden", -- src\editor\menu_search.lua
["Select and Find Previous"] = "Auswählen und vorheriges finden", -- src\editor\menu_search.lua
["Select the word under cursor and find its next occurrence"] = "Wort unter dem Cursor auswählen und nächstes Auftauchen finden", -- src\editor\menu_search.lua
["Select the word under cursor and find its previous occurrence"] = "Wort unter dem Cursor auswählen und vorheriges Auftauchen finden", -- src\editor\menu_search.lua
["Set From Current File"] = "Anhand der aktuellen Datei festlegen", -- src\editor\menu_project.lua
["Set project directory from current file"] = "Lege Projektverzeichnis anhand der aktuellen Datei fest", -- src\editor\menu_project.lua, src\editor\gui.lua
["Set project directory from current file"] = "Lege Projektverzeichnis anhand der aktuellen Datei fest", -- src\editor\gui.lua, src\editor\menu_project.lua
["Set the interpreter to be used"] = "Wähle zu benutzenden Interpreter aus", -- src\editor\menu_project.lua
["Set the project directory to be used"] = "Lege zu benutzendes Projektverzeichnis fest", -- src\editor\menu_project.lua
["Settings: System"] = "Einstellungen: System", -- src\editor\menu_edit.lua
@@ -196,25 +222,29 @@ return {
["Show &Tooltip"] = "&Tooltip zeigen", -- src\editor\menu_edit.lua
["Show Location"] = "Ordner öffnen", -- src\editor\gui.lua, src\editor\filetree.lua
["Show tooltip for current position; place cursor after opening bracket of function"] = "Zeige Tooltip für aktuelle Position; setze Cursor hinter die öffnende Klammer der Funktion", -- src\editor\menu_edit.lua
["Sort selected lines"] = "Ausgewählte Zeilen sortieren", -- src\editor\menu_search.lua
["Stack"] = "Stack", -- src\editor\debugger.lua
["Sort selected lines"] = "Ausgewählte Zeilen sortieren", -- src\editor\menu_edit.lua
["Stack"] = "Stack", -- src\editor\debugger.lua, src\editor\gui.lua
["Start &Debugging"] = "&Debugging starten", -- src\editor\menu_project.lua
["Start debugging"] = "Debugging starten", -- src\editor\menu_project.lua, src\editor\gui.lua
["Start or Continue debugging"] = "Debuggen starten/fortsetzen", -- src\editor\gui.lua
["Start or continue debugging"] = "Debuggen starten/fortsetzen", -- src\editor\menu_project.lua
["Step &Into"] = "Schritt h&inein", -- src\editor\menu_project.lua
["Step &Over"] = "&Überspringen", -- src\editor\menu_project.lua
["Step O&ut"] = "Schritt &raus", -- src\editor\menu_project.lua
["Step into"] = "Schritt hinein", -- src\editor\menu_project.lua, src\editor\gui.lua
["Step out of the current function"] = "Schritt aus der aktuellen Funktion heraus", -- src\editor\menu_project.lua, src\editor\gui.lua
["Step over"] = "Überspringen", -- src\editor\menu_project.lua, src\editor\gui.lua
["Stop the currently running process"] = "Aktuell laufenden Prozeß stoppen", -- src\editor\menu_project.lua, src\editor\gui.lua
["Step into"] = "Schritt hinein", -- src\editor\gui.lua, src\editor\menu_project.lua
["Step out of the current function"] = "Schritt aus der aktuellen Funktion heraus", -- src\editor\gui.lua, src\editor\menu_project.lua
["Step over"] = "Überspringen", -- src\editor\gui.lua, src\editor\menu_project.lua
["Stop the currently running process"] = "Aktuell laufenden Prozeß stoppen", -- src\editor\gui.lua, src\editor\menu_project.lua
["Switch to or from full screen mode"] = "Vollbild an/aus", -- src\editor\menu_view.lua
["Text not found."] = "Text nicht gefunden.", -- src\editor\findreplace.lua
["The API file must be located in a subdirectory of the API directory."] = "Die API-Datei muß sich in einem Unterverzeichnis des API-Vereichnisses befinden.", -- src\editor\autocomplete.lua
["Toggle Break&point"] = "&Haltepunkt an/aus", -- src\editor\menu_project.lua
["Toggle breakpoint"] = "Haltepunkt an/aus", -- src\editor\menu_project.lua, src\editor\gui.lua
["Toggle breakpoint"] = "Haltepunkt an/aus", -- src\editor\gui.lua, src\editor\menu_project.lua
["Tr&ace"] = "Ablauf &verfolgen", -- src\editor\menu_project.lua
["Trace execution showing each executed line"] = "Ablaufverfolgung zeigt jede ausgeführte Zeile an", -- src\editor\menu_project.lua
["Unable to create directory '%s'."] = "Kann kein Verzeichnis '%s' erstellen.", -- src\editor\filetree.lua
["Unable to create file '%s'."] = "Kann Datei '%s' nicht erstellen.", -- src\editor\filetree.lua
["Unable to load file '%s'."] = "Scheitern beim Laden von Datei '%s'.", -- src\editor\commands.lua
["Unable to rename file '%s'."] = "Kann Datei '%s' nicht umbenennen.", -- src\editor\filetree.lua
["Unable to save file '%s': %s"] = "Scheitern beim Speichern von Datei '%s' : %s", -- src\editor\commands.lua
["Unable to stop program (pid: %d), code %d."] = "Scheitern beim Stoppen des Prozesses (pid : %d), code %d.", -- src\editor\debugger.lua
["Undo last edit"] = "Letzte Änderung rückgängig machen", -- src\editor\menu_edit.lua
@@ -225,12 +255,13 @@ return {
["Value"] = "Wert", -- src\editor\debugger.lua
["View the output/console window"] = "Ausgabe-/Konsolenfenster ansehen", -- src\editor\menu_view.lua
["View the project/filetree window"] = "Projekt-/Dateifenster ansehen", -- src\editor\menu_view.lua
["View the stack window"] = "Stapel/Stack-Fenster ansehen", -- src\editor\menu_view.lua, src\editor\gui.lua
["View the watch window"] = "Fenster für Beobachtungspunkte ansehen", -- src\editor\menu_view.lua, src\editor\gui.lua
["Watch"] = "Beobachtungspunkte", -- src\editor\debugger.lua
["View the stack window"] = "Stapel/Stack-Fenster ansehen", -- src\editor\gui.lua, src\editor\menu_view.lua
["View the watch window"] = "Fenster für Beobachtungspunkte ansehen", -- src\editor\gui.lua, src\editor\menu_view.lua
["Watch"] = "Beobachtungspunkte", -- src\editor\debugger.lua, src\editor\gui.lua
["Welcome to the interactive Lua interpreter."] = "Willkommen zum interaktiven Lua-Interpretr!", -- src\editor\shellbox.lua
["Wrap ar&ound"] = "Am Anfang fortsetzen", -- src\editor\findreplace.lua
["You must save the program first."] = "Erst das Programm speichern.", -- src\editor\commands.lua
["on line %d"] = "in Zeile %d", -- src\editor\debugger.lua, src\editor\commands.lua, src\editor\editor.lua
["traced %d instruction"] = {"%d Anweisung verfolgt", "%d Anweisungen verfolgt"} -- src\editor\debugger.lua
["on line %d"] = "in Zeile %d", -- src\editor\debugger.lua, src\editor\editor.lua, src\editor\commands.lua
["traced %d instruction"] = {"%d Anweisung verfolgt", "%d Anweisungen verfolgt"}, -- src\editor\debugger.lua
["unknown error"] = "Unbekannter Fehler", -- src\editor\debugger.lua
}

View File

@@ -3,57 +3,78 @@
-- 10 de Noviembre de 2012
return {
[0] = function(c) return c == 1 and 1 or 2 end, -- plural
["%d instance"] = nil, -- src\editor\findreplace.lua
["%s event failed: %s"] = nil, -- src\editor\package.lua
["&About"] = "&Acerca de...", -- src\editor\menu_help.lua
["&Add Watch"] = "Añadir observación", -- src\editor\debugger.lua
["&Break"] = "Ruptura", -- src\editor\menu_project.lua
["&Close Page"] = "Cerrar página", -- src\editor\menu_file.lua, src\editor\gui.lua
["&Close Page"] = "Cerrar página", -- src\editor\gui.lua, src\editor\menu_file.lua
["&Community"] = nil, -- src\editor\menu_help.lua
["&Compile"] = "Compilar", -- src\editor\menu_project.lua
["&Copy"] = "Copiar", -- src\editor\editor.lua, src\editor\menu_edit.lua
["&Copy"] = "Copiar", -- src\editor\menu_edit.lua, src\editor\editor.lua
["&Default Layout"] = "Diseño por defecto", -- src\editor\menu_view.lua
["&Delete Watch"] = "Eliminar observación", -- src\editor\debugger.lua
["&Delete"] = nil, -- src\editor\filetree.lua
["&Documentation"] = nil, -- src\editor\menu_help.lua
["&Down"] = nil, -- src\editor\findreplace.lua
["&Edit Watch"] = "Editar observación", -- src\editor\debugger.lua
["&Edit"] = "Editar", -- src\editor\menu_edit.lua
["&File"] = "Archivo", -- src\editor\menu_file.lua
["&Find All"] = nil, -- src\editor\findreplace.lua
["&Find Next"] = nil, -- src\editor\findreplace.lua
["&Find"] = "Buscar", -- src\editor\menu_search.lua
["&Fold/Unfold All"] = "Plegar/desplegar todo", -- src\editor\menu_edit.lua
["&Frequently Asked Questions"] = nil, -- src\editor\menu_help.lua
["&Getting Started Guide"] = nil, -- src\editor\menu_help.lua
["&Goto Line"] = "Ir a línea", -- src\editor\menu_search.lua
["&Help"] = "Ayuda", -- src\editor\menu_help.lua
["&New Directory"] = nil, -- src\editor\filetree.lua
["&New"] = "&Nuevo", -- src\editor\menu_file.lua
["&Open..."] = "&Abrir...", -- src\editor\menu_file.lua
["&Output/Console Window"] = "Salida/Consola", -- src\editor\menu_view.lua
["&Paste"] = "Pegar", -- src\editor\editor.lua, src\editor\menu_edit.lua
["&Project"] = "Proyecto", -- src\editor\menu_project.lua, src\editor\inspect.lua
["&Redo"] = "Rehacer", -- src\editor\editor.lua, src\editor\menu_edit.lua
["&Replace"] = "Remplazar", -- src\editor\menu_search.lua
["&Paste"] = "Pegar", -- src\editor\menu_edit.lua, src\editor\editor.lua
["&Project Page"] = nil, -- src\editor\menu_help.lua
["&Project"] = "Proyecto", -- src\editor\inspect.lua, src\editor\menu_project.lua
["&Redo"] = "Rehacer", -- src\editor\menu_edit.lua, src\editor\editor.lua
["&Rename"] = nil, -- src\editor\filetree.lua
["&Replace All"] = nil, -- src\editor\findreplace.lua
["&Replace"] = "Remplazar", -- src\editor\findreplace.lua, src\editor\menu_search.lua
["&Run"] = "Ejecutar", -- src\editor\menu_project.lua
["&Save"] = "Guardar", -- src\editor\menu_file.lua, src\editor\gui.lua
["&Save"] = "Guardar", -- src\editor\gui.lua, src\editor\menu_file.lua
["&Search"] = "Buscar", -- src\editor\menu_search.lua
["&Sort"] = "Clasificar", -- src\editor\menu_search.lua
["&Sort"] = "Clasificar", -- src\editor\menu_edit.lua
["&Stack Window"] = "Ventana de la pila de ejecución", -- src\editor\menu_view.lua
["&Start Debugger Server"] = "Lanzar servidor de depuración", -- src\editor\menu_project.lua
["&Undo"] = "Deshacer", -- src\editor\editor.lua, src\editor\menu_edit.lua
["&Subdirectories"] = nil, -- src\editor\findreplace.lua
["&Tutorials"] = nil, -- src\editor\menu_help.lua
["&Undo"] = "Deshacer", -- src\editor\menu_edit.lua, src\editor\editor.lua
["&Up"] = nil, -- src\editor\findreplace.lua
["&View"] = "Ver", -- src\editor\menu_view.lua
["&Watch Window"] = "Ventana de observaciones", -- src\editor\menu_view.lua
[".&bak on Replace"] = nil, -- src\editor\findreplace.lua
["About %s"] = "Acerca de %s", -- src\editor\menu_help.lua
["Add Watch Expression"] = "Añadir expresión de observación", -- src\editor\editor.lua
["Add To Scratchpad"] = "Añadir al borrador", -- src\editor\editor.lua
["Add Watch Expression"] = "Añadir expresión de observación", -- src\editor\editor.lua
["All files"] = "Todos los archivos", -- src\editor\commands.lua
["Allow external process to start debugging"] = "Permitir proceso externo para iniciar depuración", -- src\editor\menu_project.lua
["Analyze the source code"] = "Analizar el código fuente", -- src\editor\inspect.lua
["Analyze"] = "Analizar", -- src\editor\inspect.lua
["Auto Complete Identifiers"] = "Autocompletar identificadores", -- src\editor\menu_edit.lua
["Auto complete while typing"] = "Autocompletar mientras se escribe", -- src\editor\menu_edit.lua
["Break execution at the next executed line of code"] = "Parar ejecución en la siguiente línea de código", -- src\editor\menu_project.lua, src\editor\gui.lua
["Break execution at the next executed line of code"] = "Parar ejecución en la siguiente línea de código", -- src\editor\gui.lua, src\editor\menu_project.lua
["C&lear Output Window"] = "Limpiar ventana de Salida", -- src\editor\menu_project.lua
["C&omment/Uncomment"] = "Comentar/descomentar", -- src\editor\menu_edit.lua
["Can't debug the script in the active editor window."] = "No se puede depurar el script en la ventana activa del editor", -- src\editor\debugger.lua
["Can't find file '%s' in the current project to activate for debugging. Update the project or open the file in the editor before debugging."] = "No se puede encontrar el archivo '%s' en el proyecto actual para activar la depuración. Actualiza el proyecto o abre el archivo en el editor antes de depurar.", -- src\editor\debugger.lua
["Can't process auto-recovery record; invalid format: %s."] = "No se puede procesar la autorrecuperación; formato inválido: %s.", -- src\editor\commands.lua
["Can't run the entry point script ('%s')."] = "No se pude ejecutar el punto de entrada del script (%s).", -- src\editor\debugger.lua
["Can't start debugger server at %s:%d: %s."] = nil, -- src\editor\debugger.lua
["Can't start debugging session due to internal error '%s'."] = "No se puede iniciar la sesión de depuración debido a un error interno '%s'.'", -- src\editor\debugger.lua
["Can't start debugging without an opened file or with the current file not being saved ('%s')."] = "No se puede iniciar la depuración sin abrir un archivo o si no ha sido guardado ('%s').", -- src\editor\debugger.lua
["Choose ..."] = nil, -- src\editor\menu_project.lua
["Choose a project directory"] = "Elegir el directorio del proyecto", -- src\editor\menu_project.lua
["Cancel"] = nil, -- src\editor\findreplace.lua
["Cancelled by the user."] = nil, -- src\editor\findreplace.lua
["Choose..."] = nil, -- src\editor\menu_project.lua
["Choose a project directory"] = "Elegir el directorio del proyecto", -- src\editor\findreplace.lua, src\editor\menu_project.lua
["Clear &Dynamic Words"] = "Limpiar las palabras dinámicas", -- src\editor\menu_edit.lua
["Clear the output window before compiling or debugging"] = "Limpiar la ventana de salida antes de compilar o depurar", -- src\editor\menu_project.lua
["Close &Other Pages"] = nil, -- src\editor\gui.lua
@@ -61,25 +82,33 @@ return {
["Close the current editor window"] = "Cerrar la ventana actual del editor", -- src\editor\menu_file.lua
["Co&ntinue"] = "Continuar", -- src\editor\menu_project.lua
["Col: %d"] = "Col: %d", -- src\editor\editor.lua
["Command Line Parameters..."] = nil, -- src\editor\menu_project.lua
["Command line parameters"] = nil, -- src\editor\menu_project.lua
["Comment or uncomment current or selected lines"] = {"Comentar o descomentar la línea activa (seleccionada)","Comentar o descomentar las líneas activas (seleccionadas)"}, -- src\editor\menu_edit.lua
["Compilation error"] = "Error de compilación", -- src\editor\debugger.lua, src\editor\commands.lua
["Compilation error"] = "Error de compilación", -- src\editor\commands.lua, src\editor\debugger.lua
["Compilation successful; %.0f%% success rate (%d/%d)."] = "Compilación exitosa; factor de éxito: %.0f%% (%d/%d).", -- src\editor\commands.lua
["Compile the current file"] = "Compilar el archivo actual", -- src\editor\menu_project.lua
["Complete &Identifier"] = "Completar identificador", -- src\editor\menu_edit.lua
["Complete the current identifier"] = "Completar el actual identificador", -- src\editor\menu_edit.lua
["Consider removing backslash from escape sequence '%s'."] = nil, -- src\editor\commands.lua
["Copy Full Path"] = nil, -- src\editor\filetree.lua
["Copy selected text to clipboard"] = "Copiar el texto seleccionado al portapapeles", -- src\editor\menu_edit.lua
["Couldn't activate file '%s' for debugging; continuing without it."] = "No se pudo activar el archivo '%s' para la depuración; continuar sin él.", -- src\editor\debugger.lua
["Create an empty document"] = "Crear un documento en blanco", -- src\editor\menu_file.lua, src\editor\gui.lua
["Cu&t"] = "Cortar", -- src\editor\editor.lua, src\editor\menu_edit.lua
["Create an empty document"] = "Crear un documento en blanco", -- src\editor\gui.lua, src\editor\menu_file.lua
["Cu&t"] = "Cortar", -- src\editor\menu_edit.lua, src\editor\editor.lua
["Cut selected text to clipboard"] = "Cortar el texto selecionado al portapapeles", -- src\editor\menu_edit.lua
["Debugger server started at %s:%d."] = "Servidor de depuración inciado en %s:%s", -- src\editor\debugger.lua
["Debugging session completed (%s)."] = "Sesión de depuración completada (%s).", -- src\editor\debugger.lua
["Debugging session started in '%s'."] = "Sesión de depuración iniciada en '%s'.", -- src\editor\debugger.lua
["Debugging suspended at %s:%s (couldn't activate the file)."] = nil, -- src\editor\debugger.lua
["Directory"] = nil, -- src\editor\findreplace.lua
["Do you want to delete '%s'?"] = nil, -- src\editor\filetree.lua
["Do you want to overwrite it?"] = nil, -- src\editor\commands.lua
["Do you want to reload it?"] = "¿Quieres recargarlo?", -- src\editor\editor.lua
["Do you want to save the changes to '%s'?"] = "¿Quieres guardar los cambios en '%s'?", -- src\editor\commands.lua
["E&xit"] = "Salir", -- src\editor\menu_file.lua
["Enter Lua code and press Enter to run it."] = "Introduce código Lua y pulsa <Entrer> para ejecutarlo.", -- src\editor\shellbox.lua
["Enter command line parameters (use Cancel to clear)"] = nil, -- src\editor\menu_project.lua
["Enter line number"] = "Introduce número de línea", -- src\editor\menu_search.lua
["Error while loading API file: %s"] = "Error mientras se cargaba el archivo de API: %s", -- src\editor\autocomplete.lua
["Error while loading configuration file: %s"] = nil, -- src\editor\style.lua
@@ -95,36 +124,49 @@ return {
["Expression"] = "Expresión", -- src\editor\debugger.lua
["File '%s' has been modified on disk."] = "El archivo '%s' ha sido modificado en el disco.", -- src\editor\editor.lua
["File '%s' has more recent timestamp than restored '%s'; please review before saving."] = "El archivo '%s' tiene una fecha más reciente que el restaurado '%s'; por favor, revísalo antes de guardar.", -- src\editor\commands.lua
["File '%s' no longer exists."] = "El archivo '%s' no existe.", -- src\editor\editor.lua
["File '%s' no longer exists."] = "El archivo '%s' no existe.", -- src\editor\menu_file.lua, src\editor\editor.lua
["File Type"] = nil, -- src\editor\findreplace.lua
["File already exists."] = nil, -- src\editor\commands.lua
["File history"] = "Historial de archivos", -- src\editor\menu_file.lua
["Find &In Files"] = "Buscar en archivos", -- src\editor\menu_search.lua
["Find &Next"] = "Buscar siguiente", -- src\editor\menu_search.lua
["Find &Previous"] = "Buscar anterior", -- src\editor\menu_search.lua
["Find In Files"] = nil, -- src\editor\findreplace.lua
["Find and replace text in files"] = "Buscar y remplazar texto en archivos", -- src\editor\menu_search.lua
["Find and replace text"] = "Buscar y rempleazar texto", -- src\editor\menu_search.lua, src\editor\gui.lua
["Find and replace text"] = "Buscar y rempleazar texto", -- src\editor\gui.lua, src\editor\menu_search.lua
["Find text in files"] = "Buscar texto en archivos", -- src\editor\menu_search.lua
["Find text"] = "Buscar texto", -- src\editor\menu_search.lua, src\editor\gui.lua
["Find text"] = "Buscar texto", -- src\editor\gui.lua, src\editor\menu_search.lua
["Find the earlier text occurence"] = "Buscar la anterior aparición del texto", -- src\editor\menu_search.lua
["Find the next text occurrence"] = "Buscar la siguiente aparecición del texto", -- src\editor\menu_search.lua
["Find"] = nil, -- src\editor\findreplace.lua
["Fold or unfold all code folds"] = "Plegar o desplegar todo el código plegado", -- src\editor\menu_edit.lua
["Found auto-recovery record and restored saved session."] = "Encontrada autorrecuperación y sesión restaurada.", -- src\editor\commands.lua
["Found"] = nil, -- src\editor\findreplace.lua
["Full &Screen"] = "Pantalla completa", -- src\editor\menu_view.lua
["Go To Definition"] = nil, -- src\editor\editor.lua
["Go to a selected line"] = "Ir a línea seleccionada", -- src\editor\menu_search.lua
["Goto Line"] = "Ir a línea", -- src\editor\menu_search.lua
["INS"] = "INS", -- src\editor\editor.lua
["In Files"] = nil, -- src\editor\findreplace.lua
["Jump to a function definition..."] = "Saltar a la definición de la función...", -- src\editor\editor.lua
["Known Files"] = "Archivos conocidos", -- src\editor\commands.lua
["Ln: %d"] = "Ln: %d", -- src\editor\editor.lua
["Local console"] = "Consola local", -- src\editor\shellbox.lua, src\editor\gui.lua
["Local console"] = "Consola local", -- src\editor\gui.lua, src\editor\shellbox.lua
["Lua &Interpreter"] = "Intérprete Lua", -- src\editor\menu_project.lua
["Mapped remote request for '%s' to '%s'."] = nil, -- src\editor\debugger.lua
["Match &case"] = nil, -- src\editor\findreplace.lua
["Match &whole word"] = nil, -- src\editor\findreplace.lua
["Mixed end-of-line encodings detected."] = nil, -- src\editor\commands.lua
["New &File"] = nil, -- src\editor\filetree.lua
["OVR"] = "OVR", -- src\editor\editor.lua
["Open an existing document"] = "Abrir un documento existente", -- src\editor\menu_file.lua, src\editor\gui.lua
["Open With Default Program"] = nil, -- src\editor\filetree.lua
["Open an existing document"] = "Abrir un documento existente", -- src\editor\gui.lua, src\editor\menu_file.lua
["Open file"] = "Abrir archivo", -- src\editor\commands.lua
["Options"] = nil, -- src\editor\findreplace.lua
["Output (running)"] = "Salida (en ejecución)", -- src\editor\output.lua
["Output"] = "Salida", -- src\editor\output.lua, src\editor\settings.lua, src\editor\gui.lua
["Output"] = "Salida", -- src\editor\gui.lua, src\editor\output.lua, src\editor\settings.lua
["Paste text from the clipboard"] = "Pegar texto desde el portapapeles", -- src\editor\menu_edit.lua
["Preferences"] = nil, -- src\editor\menu_edit.lua
["Prepend '=' to show complex values on multiple lines."] = "Antepón '=' para ver valores complejos en líneas múltiples", -- src\editor\shellbox.lua
["Press cancel to abort."] = "Presiona cancelar para abortar.", -- src\editor\commands.lua
["Program '%s' started in '%s' (pid: %d)."] = "Programa '%s' iniciado en '%s' (pid: %d).", -- src\editor\output.lua
@@ -134,57 +176,78 @@ return {
["Program stopped (pid: %d)."] = "Programa parado (pid: %d).", -- src\editor\debugger.lua
["Program unable to run as '%s'."] = "No se puede ejecutar el programa como '%s'.", -- src\editor\output.lua
["Project Directory"] = nil, -- src\editor\menu_project.lua
["Project"] = "Proyecto", -- src\editor\settings.lua, src\editor\gui.lua
["Project"] = "Proyecto", -- src\editor\gui.lua, src\editor\settings.lua
["Project/&FileTree Window"] = "Ventana de proyecto/árbol de archivos", -- src\editor\menu_view.lua
["Provide command line parameters"] = nil, -- src\editor\menu_project.lua
["R/O"] = "R/O", -- src\editor\editor.lua
["R/W"] = "R/W", -- src\editor\editor.lua
["Re&place In Files"] = "Remplazar en archivos", -- src\editor\menu_search.lua
["Recent Files"] = "Archivos recientes", -- src\editor\menu_file.lua
["Redo last edit undone"] = "Rehacer la última edición deshecha", -- src\editor\menu_edit.lua
["Refused a request to start a new debugging session as there is one in progress already."] = "No se pudo lanzar una nueva sesión de depuración porque ya hay una en curso.", -- src\editor\debugger.lua
["Regular &expression"] = nil, -- src\editor\findreplace.lua
["Remote console"] = "Consola remota", -- src\editor\shellbox.lua
["Rename All Instances"] = nil, -- src\editor\editor.lua
["Replace A&ll"] = nil, -- src\editor\findreplace.lua
["Replace"] = nil, -- src\editor\findreplace.lua
["Replaced an invalid UTF8 character with %s."] = nil, -- src\editor\commands.lua
["Replaced"] = nil, -- src\editor\findreplace.lua
["Replacing"] = nil, -- src\editor\findreplace.lua
["Reset to default layout"] = "Restablecer el diseño por defecto", -- src\editor\menu_view.lua
["Resets the dynamic word list for autocompletion"] = "Restablecer la lista dinámica de palabras para autocompletado", -- src\editor\menu_edit.lua
["Run as Scratchpad"] = "Ejecutar como borrador", -- src\editor\menu_project.lua
["S&top Debugging"] = "Parar depuración", -- src\editor\menu_project.lua
["S&top Process"] = "Parar proceso", -- src\editor\menu_project.lua
["Save &As..."] = "Guardar como...", -- src\editor\menu_file.lua, src\editor\gui.lua
["Save &As..."] = "Guardar como...", -- src\editor\gui.lua, src\editor\menu_file.lua
["Save A&ll"] = "Guardar todo", -- src\editor\menu_file.lua
["Save Changes?"] = "¿Guardar cambios?", -- src\editor\commands.lua
["Save all open documents"] = "Guardar todos los documentos abiertos", -- src\editor\menu_file.lua, src\editor\gui.lua
["Save all open documents"] = "Guardar todos los documentos abiertos", -- src\editor\gui.lua, src\editor\menu_file.lua
["Save file as"] = "Guardar archivo como", -- src\editor\commands.lua
["Save file?"] = "¿Guardar archivo?", -- src\editor\commands.lua
["Save the current document to a file with a new name"] = "Guardar el documento actual en un archivo con un nombre nuevo", -- src\editor\menu_file.lua
["Save the current document"] = "Guardar el documento actual", -- src\editor\menu_file.lua, src\editor\gui.lua
["Save the current document"] = "Guardar el documento actual", -- src\editor\gui.lua, src\editor\menu_file.lua
["Saved auto-recover at %s."] = "Guardar autorrecuperación en %s.", -- src\editor\commands.lua
["Scope"] = nil, -- src\editor\findreplace.lua
["Scratchpad error"] = "Error en el borrador", -- src\editor\debugger.lua
["Select &All"] = "Seleccionar todo", -- src\editor\editor.lua, src\editor\menu_edit.lua
["Searching for"] = nil, -- src\editor\findreplace.lua
["Select &All"] = "Seleccionar todo", -- src\editor\menu_edit.lua, src\editor\editor.lua
["Select all text in the editor"] = "Seleccionar todo el texto en el editor", -- src\editor\menu_edit.lua
["Select and Find Next"] = nil, -- src\editor\menu_search.lua
["Select and Find Previous"] = nil, -- src\editor\menu_search.lua
["Select the word under cursor and find its next occurrence"] = nil, -- src\editor\menu_search.lua
["Select the word under cursor and find its previous occurrence"] = nil, -- src\editor\menu_search.lua
["Set From Current File"] = nil, -- src\editor\menu_project.lua
["Set project directory from current file"] = "Establecer el directorio del proyecto del archivo actual", -- src\editor\menu_project.lua, src\editor\gui.lua
["Set project directory from current file"] = "Establecer el directorio del proyecto del archivo actual", -- src\editor\gui.lua, src\editor\menu_project.lua
["Set the interpreter to be used"] = "Establecer el intérprete a ser usado", -- src\editor\menu_project.lua
["Set the project directory to be used"] = nil, -- src\editor\menu_project.lua
["Settings: System"] = nil, -- src\editor\menu_edit.lua
["Settings: User"] = nil, -- src\editor\menu_edit.lua
["Show &Tooltip"] = "Ver tooltip", -- src\editor\menu_edit.lua
["Show Location"] = nil, -- src\editor\gui.lua, src\editor\filetree.lua
["Show tooltip for current position; place cursor after opening bracket of function"] = "Ver tooltip para la posición actual; posicionar el cursor después de abrir el paréntisis de los argumentos de la función", -- src\editor\menu_edit.lua
["Sort selected lines"] = "Clasificar las líneas seleccionadas", -- src\editor\menu_search.lua
["Stack"] = nil, -- src\editor\debugger.lua
["Sort selected lines"] = "Clasificar las líneas seleccionadas", -- src\editor\menu_edit.lua
["Stack"] = nil, -- src\editor\debugger.lua, src\editor\gui.lua
["Start &Debugging"] = "Comenzar depuración", -- src\editor\menu_project.lua
["Start debugging"] = "Comenzar depuración", -- src\editor\menu_project.lua, src\editor\gui.lua
["Start or Continue debugging"] = nil, -- src\editor\gui.lua
["Start or continue debugging"] = nil, -- src\editor\menu_project.lua
["Step &Into"] = "Paso dentro", -- src\editor\menu_project.lua
["Step &Over"] = "Paso sin entrar", -- src\editor\menu_project.lua
["Step O&ut"] = "Paso fuera", -- src\editor\menu_project.lua
["Step into"] = "Paso dentro", -- src\editor\menu_project.lua, src\editor\gui.lua
["Step out of the current function"] = "Hasta salir de la función actual", -- src\editor\menu_project.lua, src\editor\gui.lua
["Step over"] = "Paso sin entrar", -- src\editor\menu_project.lua, src\editor\gui.lua
["Stop the currently running process"] = "Parar el proceso en ejecución", -- src\editor\menu_project.lua, src\editor\gui.lua
["Step into"] = "Paso dentro", -- src\editor\gui.lua, src\editor\menu_project.lua
["Step out of the current function"] = "Hasta salir de la función actual", -- src\editor\gui.lua, src\editor\menu_project.lua
["Step over"] = "Paso sin entrar", -- src\editor\gui.lua, src\editor\menu_project.lua
["Stop the currently running process"] = "Parar el proceso en ejecución", -- src\editor\gui.lua, src\editor\menu_project.lua
["Switch to or from full screen mode"] = "Conmutar el modo de pantalla completa", -- src\editor\menu_view.lua
["Text not found."] = nil, -- src\editor\findreplace.lua
["The API file must be located in a subdirectory of the API directory."] = "El archivo de API debe ser almacenado en un subdirectorio del directorio de API.", -- src\editor\autocomplete.lua
["Toggle Break&point"] = "Conmutar punto de ruptura", -- src\editor\menu_project.lua
["Toggle breakpoint"] = "Conmutar punto de ruptura", -- src\editor\menu_project.lua, src\editor\gui.lua
["Toggle breakpoint"] = "Conmutar punto de ruptura", -- src\editor\gui.lua, src\editor\menu_project.lua
["Tr&ace"] = "Traza", -- src\editor\menu_project.lua
["Trace execution showing each executed line"] = "Traza de ejecución mostrando cada línea ejecutada", -- src\editor\menu_project.lua
["Unable to create directory '%s'."] = nil, -- src\editor\filetree.lua
["Unable to create file '%s'."] = nil, -- src\editor\filetree.lua
["Unable to load file '%s'."] = "No se pudo cargar el archivo '%s'.", -- src\editor\commands.lua
["Unable to rename file '%s'."] = nil, -- src\editor\filetree.lua
["Unable to save file '%s': %s"] = "No se pudo guardar el archivo '%s': %s", -- src\editor\commands.lua
["Unable to stop program (pid: %d), code %d."] = "No se puedo parar el programa (pid: %d), código %d.", -- src\editor\debugger.lua
["Undo last edit"] = "Deshacer la última edición", -- src\editor\menu_edit.lua
@@ -195,11 +258,13 @@ return {
["Value"] = "Valor", -- src\editor\debugger.lua
["View the output/console window"] = "Ver ventana de salida/consola", -- src\editor\menu_view.lua
["View the project/filetree window"] = "Ver la ventana de proyecto/árbol de archivos", -- src\editor\menu_view.lua
["View the stack window"] = "Ver la ventana de la pila de ejecución", -- src\editor\menu_view.lua, src\editor\gui.lua
["View the watch window"] = "Ver la ventana de observación", -- src\editor\menu_view.lua, src\editor\gui.lua
["Watch"] = nil, -- src\editor\debugger.lua
["View the stack window"] = "Ver la ventana de la pila de ejecución", -- src\editor\gui.lua, src\editor\menu_view.lua
["View the watch window"] = "Ver la ventana de observación", -- src\editor\gui.lua, src\editor\menu_view.lua
["Watch"] = nil, -- src\editor\debugger.lua, src\editor\gui.lua
["Welcome to the interactive Lua interpreter."] = "Bienvenido al intérprete interactico de Lua.", -- src\editor\shellbox.lua
["Wrap ar&ound"] = nil, -- src\editor\findreplace.lua
["You must save the program first."] = "Debes guardar el programa primero", -- src\editor\commands.lua
["on line %d"] = "en la línea %d", -- src\editor\debugger.lua, src\editor\commands.lua
["traced %d instruction"] = {"%d instrucción trazada", "%d instrucciones trazadas"} -- src\editor\debugger.lua
["on line %d"] = "en la línea %d", -- src\editor\debugger.lua, src\editor\editor.lua, src\editor\commands.lua
["traced %d instruction"] = {"%d instrucción trazada", "%d instrucciones trazadas"}, -- src\editor\debugger.lua
["unknown error"] = nil, -- src\editor\debugger.lua
}

View File

@@ -5,11 +5,14 @@ return {
["&About"] = "À &propos", -- src\editor\menu_help.lua
["&Add Watch"] = "&Ajouter une expression", -- src\editor\debugger.lua
["&Break"] = "&Interrompre", -- src\editor\menu_project.lua
["&Close Page"] = "&Fermer la page", -- src\editor\menu_file.lua, src\editor\gui.lua
["&Close Page"] = "&Fermer la page", -- src\editor\gui.lua, src\editor\menu_file.lua
["&Community"] = "&Communauté", -- src\editor\menu_help.lua
["&Compile"] = "&Compiler", -- src\editor\menu_project.lua
["&Copy"] = "Co&pier", -- src\editor\editor.lua, src\editor\menu_edit.lua
["&Copy"] = "Co&pier", -- src\editor\menu_edit.lua, src\editor\editor.lua
["&Default Layout"] = "Affichage par &défaut", -- src\editor\menu_view.lua
["&Delete Watch"] = "&Supprimer une expression", -- src\editor\debugger.lua
["&Delete"] = "&Supprimer", -- src\editor\filetree.lua
["&Documentation"] = "&Documentation", -- src\editor\menu_help.lua
["&Down"] = "Vers le &bas", -- src\editor\findreplace.lua
["&Edit Watch"] = "&Modifier une expression", -- src\editor\debugger.lua
["&Edit"] = "É&dition", -- src\editor\menu_edit.lua
@@ -18,48 +21,56 @@ return {
["&Find Next"] = "&Rechercher", -- src\editor\findreplace.lua
["&Find"] = "&Rechercher", -- src\editor\menu_search.lua
["&Fold/Unfold All"] = "Re&plier/Déplier tout", -- src\editor\menu_edit.lua
["&Frequently Asked Questions"] = "&Questions Fréquemment Posées" , -- src\editor\menu_help.lua
["&Getting Started Guide"] = "&Guide de Prise en Main", -- src\editor\menu_help.lua
["&Goto Line"] = "&Aller à la ligne", -- src\editor\menu_search.lua
["&Help"] = "Aid&e", -- src\editor\menu_help.lua
["&New Directory"] = "&Nouveau Répertoire", -- src\editor\filetree.lua
["&New"] = "&Nouveau", -- src\editor\menu_file.lua
["&Open..."] = "&Ouvrir...", -- src\editor\menu_file.lua
["&Output/Console Window"] = "&Sortie/Console", -- src\editor\menu_view.lua
["&Paste"] = "Co&ller", -- src\editor\editor.lua, src\editor\menu_edit.lua
["&Project"] = "&Projet", -- src\editor\menu_project.lua, src\editor\inspect.lua
["&Redo"] = "&Rétablir", -- src\editor\editor.lua, src\editor\menu_edit.lua
["&Paste"] = "Co&ller", -- src\editor\menu_edit.lua, src\editor\editor.lua
["&Project Page"] = "&Site Web de ZeroBrane", -- src\editor\menu_help.lua
["&Project"] = "&Projet", -- src\editor\inspect.lua, src\editor\menu_project.lua
["&Redo"] = "&Rétablir", -- src\editor\menu_edit.lua, src\editor\editor.lua
["&Rename"] = "&Renommer", -- src\editor\filetree.lua
["&Replace All"] = "Remplacer &tout", -- src\editor\findreplace.lua
["&Replace"] = "Re&mplacer", -- src\editor\findreplace.lua, src\editor\menu_search.lua
["&Run"] = "&Exécuter", -- src\editor\menu_project.lua
["&Save"] = "&Enregistrer", -- src\editor\menu_file.lua, src\editor\gui.lua
["&Save"] = "&Enregistrer", -- src\editor\gui.lua, src\editor\menu_file.lua
["&Search"] = "&Recherche", -- src\editor\menu_search.lua
["&Sort"] = "&Trier", -- src\editor\menu_search.lua
["&Sort"] = "&Trier", -- src\editor\menu_edit.lua
["&Stack Window"] = "&Pile d'exécution", -- src\editor\menu_view.lua
["&Start Debugger Server"] = "Lancer le &serveur de débogage", -- src\editor\menu_project.lua
["&Subdirectories"] = "&Sous-répertoires", -- src\editor\findreplace.lua
["&Undo"] = "&Annuler", -- src\editor\editor.lua, src\editor\menu_edit.lua
["&Tutorials"] = "&Tutoriels", -- src\editor\menu_help.lua
["&Undo"] = "&Annuler", -- src\editor\menu_edit.lua, src\editor\editor.lua
["&Up"] = "Vers le &haut", -- src\editor\findreplace.lua
["&View"] = "&Affichage", -- src\editor\menu_view.lua
["&Watch Window"] = "&Expressions espionnes", -- src\editor\menu_view.lua
[".&bak on Replace"] = ".&bak avant remplacement", -- src\editor\findreplace.lua
["About %s"] = "À propos de %s", -- src\editor\menu_help.lua
["Add Watch Expression"] = "Ajouter une expression", -- src\editor\editor.lua
["Add To Scratchpad"] = "Ajouter au brouillon", -- src\editor\editor.lua
["Add Watch Expression"] = "Ajouter une expression", -- src\editor\editor.lua
["All files"] = "Tous les fichiers", -- src\editor\commands.lua
["Allow external process to start debugging"] = "Autoriser les processus externes à lancer le débogage", -- src\editor\menu_project.lua
["Analyze the source code"] = "Analyser le code source", -- src\editor\inspect.lua
["Analyze"] = "Analyser", -- src\editor\inspect.lua
["Auto Complete Identifiers"] = "Auto-compléter les identifiants", -- src\editor\menu_edit.lua
["Auto complete while typing"] = "Auto-compléter lors de la saisie", -- src\editor\menu_edit.lua
["Break execution at the next executed line of code"] = "Interrompre l'exécution à la ligne suivante", -- src\editor\menu_project.lua, src\editor\gui.lua
["Break execution at the next executed line of code"] = "Interrompre l'exécution à la ligne suivante", -- src\editor\gui.lua, src\editor\menu_project.lua
["C&lear Output Window"] = "E&ffacer la fenêtre de sortie", -- src\editor\menu_project.lua
["C&omment/Uncomment"] = "Co&mmenter/Décommenter", -- src\editor\menu_edit.lua
["Can't debug the script in the active editor window."] = "Impossible de déboguer le script dans la fenêtre d'édition active.", -- src\editor\debugger.lua
["Can't find file '%s' in the current project to activate for debugging. Update the project or open the file in the editor before debugging."] = "Impossible de trouver le fichier '%s' dans le projet courant pour permettre le débogage. Mettez le projet à jour ou ouvrez le fichier dans l'éditeur avant débogage.", -- src\editor\debugger.lua
["Can't process auto-recovery record; invalid format: %s."] = "Impossible de lire la récupération automatique ; format invalide : %s.", -- src\editor\commands.lua
["Can't run the entry point script ('%s')."] = "Impossible d'exécuter le point d'entrée du script ('%s').", -- src\editor\debugger.lua
["Can't start debugger server at %s:%d: %s."] = "Impossible de lancer le serveur de débogage à %s:%d: %s." , -- src\editor\debugger.lua
["Can't start debugging session due to internal error '%s'."] = "Impossible de lancer la session de débogage : erreur interne '%s'.", -- src\editor\debugger.lua
["Can't start debugging without an opened file or with the current file not being saved ('%s')."] = "Impossible de lancer le débogage si aucun fichier n'est ouvert ou si le fichier courant n'a pas été enregistré ('%s').", -- src\editor\debugger.lua
["Cancel"] = "Annuler", -- src\editor\findreplace.lua
["Choose ..."] = "Choisir...", -- src\editor\menu_project.lua
["Cancelled by the user."] = "Annulé par l'utilisateur.", -- src\editor\findreplace.lua
["Choose..."] = "Choisir...", -- src\editor\menu_project.lua
["Choose a project directory"] = "Choisissez un répertoire de projet", -- src\editor\findreplace.lua, src\editor\menu_project.lua
["Clear &Dynamic Words"] = "Effacer les mots &dynamiques", -- src\editor\menu_edit.lua
["Clear the output window before compiling or debugging"] = "Effacer la fenêtre de sortie avant compilation ou débogage", -- src\editor\menu_project.lua
@@ -68,26 +79,33 @@ return {
["Close the current editor window"] = "Fermer la fenêtre d'édition active", -- src\editor\menu_file.lua
["Co&ntinue"] = "Co&ntinuer", -- src\editor\menu_project.lua
["Col: %d"] = "Col : %d", -- src\editor\editor.lua
["Command Line Parameters..."] = "Paramètres de Ligne de Commande...", -- src\editor\menu_project.lua
["Command line parameters"] = "Paramètres de ligne de commande", -- src\editor\menu_project.lua
["Comment or uncomment current or selected lines"] = "Commenter ou décommenter les lignes courantes ou sélectionnées", -- src\editor\menu_edit.lua
["Compilation error"] = "Erreur de compilation", -- src\editor\debugger.lua, src\editor\commands.lua
["Compilation error"] = "Erreur de compilation", -- src\editor\commands.lua, src\editor\debugger.lua
["Compilation successful; %.0f%% success rate (%d/%d)."] = "Compilation réussie ; taux de succès : %.0f%% (%d/%d).", -- src\editor\commands.lua
["Compile the current file"] = "Сompiler le fichier courant", -- src\editor\menu_project.lua
["Complete &Identifier"] = "Compléter l'&identifiant", -- src\editor\menu_edit.lua
["Complete the current identifier"] = "Compléter l'identifiant courant", -- src\editor\menu_edit.lua
["Consider removing backslash from escape sequence '%s'."] = "Essayez de supprimer les antislashs dans '%s'.", -- src\editor\commands.lua
["Copy Full Path"] = "Copier le chemin absolu", -- src\editor\filetree.lua
["Copy selected text to clipboard"] = "Copier le texte sélectionné dans le presse-papiers", -- src\editor\menu_edit.lua
["Couldn't activate file '%s' for debugging; continuing without it."] = "Impossible d'activer le fichier '%s' pour débogage ; poursuite du processus en ignorant le fichier.", -- src\editor\debugger.lua
["Create an empty document"] = "Créer un document vierge", -- src\editor\menu_file.lua, src\editor\gui.lua
["Cu&t"] = "&Couper", -- src\editor\editor.lua, src\editor\menu_edit.lua
["Create an empty document"] = "Créer un document vierge", -- src\editor\gui.lua, src\editor\menu_file.lua
["Cu&t"] = "&Couper", -- src\editor\menu_edit.lua, src\editor\editor.lua
["Cut selected text to clipboard"] = "Couper le texte sélectionné et copier dans le presse-papiers", -- src\editor\menu_edit.lua
["Debugger server started at %s:%d."] = "Serveur de débogage démarré à %s:%d.", -- src\editor\debugger.lua
["Debugging session completed (%s)."] = "Session de débogage terminée (%s).", -- src\editor\debugger.lua
["Debugging session started in '%s'."] = "Session de débogage démarrée dans '%s'.", -- src\editor\debugger.lua
["Debugging suspended at %s:%s (couldn't activate the file)."] = "Débogage interrompu à %s:%s (impossible d'activer le fichier).", -- src\editor\debugger.lua
["Directory"] = "Répertoire ", -- src\editor\findreplace.lua
["Do you want to delete '%s'?"] = "Voulez-vous effacer '%s'?", -- src\editor\filetree.lua
["Do you want to overwrite it?"] = "Voulez-vous l'écraser?", -- src\editor\commands.lua
["Do you want to reload it?"] = "Voulez-vous le recharger ?", -- src\editor\editor.lua
["Do you want to save the changes to '%s'?"] = "Voulez-vous enregistrer les modifications dans '%s' ?", -- src\editor\commands.lua
["E&xit"] = "&Quitter", -- src\editor\menu_file.lua
["Enter Lua code and press Enter to run it."] = "Saisissez du code Lua et appuyez sur <Entrée> pour l´exécuter.", -- src\editor\shellbox.lua
["Enter command line parameters (use Cancel to clear)"] = "Entrez des paramètres de ligne de commande (pressez Annuler pour effacer)", -- src\editor\menu_project.lua
["Enter line number"] = "Entrez le numéro de ligne", -- src\editor\menu_search.lua
["Error while loading API file: %s"] = "Erreur lors du chargement du fichier d'API : %s", -- src\editor\autocomplete.lua
["Error while loading configuration file: %s"] = "Erreur lors du chargement du fichier de configuration : %s", -- src\editor\style.lua
@@ -103,17 +121,18 @@ return {
["Expression"] = "Expression", -- src\editor\debugger.lua
["File '%s' has been modified on disk."] = "Le fichier '%s' a été modifié sur le disque.", -- src\editor\editor.lua
["File '%s' has more recent timestamp than restored '%s'; please review before saving."] = "Le fichier '%s' a un horodatage plus récent que celui restauré '%s' ; veuillez vérifier avant d'enregistrer.", -- src\editor\commands.lua
["File '%s' no longer exists."] = "Le fichier '%s' n'existe plus.", -- src\editor\editor.lua, src\editor\menu_file.lua
["File '%s' no longer exists."] = "Le fichier '%s' n'existe plus.", -- src\editor\menu_file.lua, src\editor\editor.lua
["File Type"] = "Type de fichier ", -- src\editor\findreplace.lua
["File already exists."] = "Le fichier existe déjà.", -- src\editor\commands.lua
["File history"] = "Historique de fichier", -- src\editor\menu_file.lua
["Find &In Files"] = "Rec&hercher dans les fichiers", -- src\editor\menu_search.lua
["Find &Next"] = "Rechercher l'occurrence &suivante", -- src\editor\menu_search.lua
["Find &Previous"] = "Rechercher l'occurrence &précédente", -- src\editor\menu_search.lua
["Find In Files"] = "Rechercher dans les fichiers", -- src\editor\findreplace.lua
["Find and replace text in files"] = "Rechercher et remplacer le texte dans les fichiers", -- src\editor\menu_search.lua
["Find and replace text"] = "Rechercher et remplacer le texte", -- src\editor\menu_search.lua, src\editor\gui.lua
["Find and replace text"] = "Rechercher et remplacer le texte", -- src\editor\gui.lua, src\editor\menu_search.lua
["Find text in files"] = "Rechercher le texte dans les fichiers", -- src\editor\menu_search.lua
["Find text"] = "Rechercher le texte", -- src\editor\menu_search.lua, src\editor\gui.lua
["Find text"] = "Rechercher le texte", -- src\editor\gui.lua, src\editor\menu_search.lua
["Find the earlier text occurence"] = "Recherche l'occurrence précédente du texte", -- src\editor\menu_search.lua
["Find the next text occurrence"] = "Recherche l'occurrence suivante du texte", -- src\editor\menu_search.lua
["Find"] = "Rechercher ", -- src\editor\findreplace.lua
@@ -129,18 +148,20 @@ return {
["Jump to a function definition..."] = "Aller à la définition de fonction...", -- src\editor\editor.lua
["Known Files"] = "Fichiers connus", -- src\editor\commands.lua
["Ln: %d"] = "Lig : %d", -- src\editor\editor.lua
["Local console"] = "Console locale", -- src\editor\shellbox.lua, src\editor\gui.lua
["Local console"] = "Console locale", -- src\editor\gui.lua, src\editor\shellbox.lua
["Lua &Interpreter"] = "Interpréteur L&ua", -- src\editor\menu_project.lua
["Mapped remote request for '%s' to '%s'."] = "La requête distante pour '%s' a été associée à '%s'.", -- src\editor\debugger.lua
["Match &case"] = "Respecter la &casse", -- src\editor\findreplace.lua
["Match &whole word"] = "&Mot entier uniquement", -- src\editor\findreplace.lua
["Mixed end-of-line encodings detected."] = "Plusieurs codages de fin de ligne détectés.", -- src\editor\commands.lua
["New &File"] = "Nouveau &Fichier", -- src\editor\filetree.lua
["OVR"] = "OVR", -- src\editor\editor.lua
["Open an existing document"] = "Ouvrir un document existant", -- src\editor\menu_file.lua, src\editor\gui.lua
["Open With Default Program"] = "Ouvrir avec le programme par défaut", -- src\editor\filetree.lua
["Open an existing document"] = "Ouvrir un document existant", -- src\editor\gui.lua, src\editor\menu_file.lua
["Open file"] = "Ouvrir un fichier", -- src\editor\commands.lua
["Options"] = "Options", -- src\editor\findreplace.lua
["Output (running)"] = "Sortie (en cours d'exécution)", -- src\editor\output.lua
["Output"] = "Sortie", -- src\editor\output.lua, src\editor\settings.lua, src\editor\gui.lua
["Output"] = "Sortie", -- src\editor\gui.lua, src\editor\output.lua, src\editor\settings.lua
["Paste text from the clipboard"] = "Coller le texte depuis le presse-papiers", -- src\editor\menu_edit.lua
["Preferences"] = "Préférences", -- src\editor\menu_edit.lua
["Prepend '=' to show complex values on multiple lines."] = "Préfixez par '=' pour afficher les valeurs complexes sur plusieurs lignes.", -- src\editor\shellbox.lua
@@ -152,8 +173,9 @@ return {
["Program stopped (pid: %d)."] = "Programme stoppé (pid : %d).", -- src\editor\debugger.lua
["Program unable to run as '%s'."] = "Impossible d'exécuter le programme en tant que '%s'.", -- src\editor\output.lua
["Project Directory"] = "Répertoire de projet", -- src\editor\menu_project.lua
["Project"] = "Projet", -- src\editor\settings.lua, src\editor\gui.lua
["Project"] = "Projet", -- src\editor\gui.lua, src\editor\settings.lua
["Project/&FileTree Window"] = "&Explorateur de projet", -- src\editor\menu_view.lua
["Provide command line parameters"] = "Renseignez les paramètres de ligne de commande", -- src\editor\menu_project.lua
["R/O"] = "R/O", -- src\editor\editor.lua
["R/W"] = "R/W", -- src\editor\editor.lua
["Re&place In Files"] = "Remp&lacer dans les fichiers", -- src\editor\menu_search.lua
@@ -163,7 +185,7 @@ return {
["Regular &expression"] = "&Expression régulière", -- src\editor\findreplace.lua
["Remote console"] = "Console à distance", -- src\editor\shellbox.lua
["Rename All Instances"] = "Renommer toutes les occurrences", -- src\editor\editor.lua
["Replace &All"] = "Remplacer &tout", -- src\editor\findreplace.lua
["Replace A&ll"] = "Remplacer &tout", -- src\editor\findreplace.lua
["Replace"] = "Remplacer par ", -- src\editor\findreplace.lua
["Replaced an invalid UTF8 character with %s."] = "Un caractère UTF8 invalide a été remplacé par %s.", -- src\editor\commands.lua
["Replaced"] = "Occurrences remplacées :", -- src\editor\findreplace.lua
@@ -173,22 +195,26 @@ return {
["Run as Scratchpad"] = "Exécuter comme brouillon", -- src\editor\menu_project.lua
["S&top Debugging"] = "&Arrêter le débogage", -- src\editor\menu_project.lua
["S&top Process"] = "&Arrêter le processus", -- src\editor\menu_project.lua
["Save &As..."] = "Enregistrer &sous...", -- src\editor\menu_file.lua, src\editor\gui.lua
["Save &As..."] = "Enregistrer &sous...", -- src\editor\gui.lua, src\editor\menu_file.lua
["Save A&ll"] = "Enregistrer &tout", -- src\editor\menu_file.lua
["Save Changes?"] = "Enregistrer les modifications ?", -- src\editor\commands.lua
["Save all open documents"] = "Enregistrer tous les documents ouverts", -- src\editor\menu_file.lua, src\editor\gui.lua
["Save all open documents"] = "Enregistrer tous les documents ouverts", -- src\editor\gui.lua, src\editor\menu_file.lua
["Save file as"] = "Enregistrer le fichier sous", -- src\editor\commands.lua
["Save file?"] = "Enregistrer le fichier ?", -- src\editor\commands.lua
["Save the current document to a file with a new name"] = "Enregistrer le document courant sous un nouveau nom", -- src\editor\menu_file.lua
["Save the current document"] = "Enregistrer le document courant", -- src\editor\menu_file.lua, src\editor\gui.lua
["Save the current document"] = "Enregistrer le document courant", -- src\editor\gui.lua, src\editor\menu_file.lua
["Saved auto-recover at %s."] = "Récup. auto enregistrée à %s.", -- src\editor\commands.lua
["Scope"] = "Direction", -- src\editor\findreplace.lua
["Scratchpad error"] = "Erreur dans le brouillon", -- src\editor\debugger.lua
["Searching for"] = "Recherche de", -- src\editor\findreplace.lua
["Select &All"] = "Sélectionner &tout", -- src\editor\editor.lua, src\editor\menu_edit.lua
["Select &All"] = "Sélectionner &tout", -- src\editor\menu_edit.lua, src\editor\editor.lua
["Select all text in the editor"] = "Sélectionner tout le texte dans l'éditeur", -- src\editor\menu_edit.lua
["Select and Find Next"] = "Sélectionner et chercher le suivant", -- src\editor\menu_search.lua
["Select and Find Previous"] = "Sélectionner et chercher le précédent", -- src\editor\menu_search.lua
["Select the word under cursor and find its next occurrence"] = "Sélectionner le mot sous le curseur et chercher son occurence suivante", -- src\editor\menu_search.lua
["Select the word under cursor and find its previous occurrence"] = "Sélectionner le mot sous le curseur et chercher son occurence précédente", -- src\editor\menu_search.lua
["Set From Current File"] = "Définir depuis le fichier courant", -- src\editor\menu_project.lua
["Set project directory from current file"] = "Définir le répertoire de projet depuis le fichier courant", -- src\editor\menu_project.lua, src\editor\gui.lua
["Set project directory from current file"] = "Définir le répertoire de projet depuis le fichier courant", -- src\editor\gui.lua, src\editor\menu_project.lua
["Set the interpreter to be used"] = "Définir l'interpréteur à utiliser", -- src\editor\menu_project.lua
["Set the project directory to be used"] = "Définir le répertoire de projet à utiliser", -- src\editor\menu_project.lua
["Settings: System"] = "Paramètres : Système", -- src\editor\menu_edit.lua
@@ -196,25 +222,29 @@ return {
["Show &Tooltip"] = "Afficher l'info-&bulle", -- src\editor\menu_edit.lua
["Show Location"] = "Afficher l'emplacement", -- src\editor\gui.lua, src\editor\filetree.lua
["Show tooltip for current position; place cursor after opening bracket of function"] = "Afficher l'info-bulle pour la position actuelle ; placez le curseur après la parenthèse ouvrante de la fonction", -- src\editor\menu_edit.lua
["Sort selected lines"] = "Trier les lignes sélectionnées", -- src\editor\menu_search.lua
["Stack"] = "Pile d'exécution", -- src\editor\debugger.lua
["Sort selected lines"] = "Trier les lignes sélectionnées", -- src\editor\menu_edit.lua
["Stack"] = "Pile d'exécution", -- src\editor\debugger.lua, src\editor\gui.lua
["Start &Debugging"] = "Lancer le &débogage", -- src\editor\menu_project.lua
["Start debugging"] = "Lancer le débogage", -- src\editor\menu_project.lua, src\editor\gui.lua
["Start or Continue debugging"] = "Démarrer ou Continuer le debogage", -- src\editor\gui.lua
["Start or continue debugging"] = "Démarrer ou continuer le debogage", -- src\editor\menu_project.lua
["Step &Into"] = "Pas à pas détai&llé", -- src\editor\menu_project.lua
["Step &Over"] = "Pas à pas so&mmaire", -- src\editor\menu_project.lua
["Step O&ut"] = "Pas à pas so&rtant", -- src\editor\menu_project.lua
["Step into"] = "Rentrer dans l'instruction suivante", -- src\editor\menu_project.lua, src\editor\gui.lua
["Step out of the current function"] = "Sortir de la fonction courante", -- src\editor\menu_project.lua, src\editor\gui.lua
["Step over"] = "Enjamber l'instruction suivante", -- src\editor\menu_project.lua, src\editor\gui.lua
["Stop the currently running process"] = "Arrêter le processus en cours d'exécution", -- src\editor\menu_project.lua, src\editor\gui.lua
["Step into"] = "Rentrer dans l'instruction suivante", -- src\editor\gui.lua, src\editor\menu_project.lua
["Step out of the current function"] = "Sortir de la fonction courante", -- src\editor\gui.lua, src\editor\menu_project.lua
["Step over"] = "Enjamber l'instruction suivante", -- src\editor\gui.lua, src\editor\menu_project.lua
["Stop the currently running process"] = "Arrêter le processus en cours d'exécution", -- src\editor\gui.lua, src\editor\menu_project.lua
["Switch to or from full screen mode"] = "Activer ou désactiver le mode plein écran", -- src\editor\menu_view.lua
["Text not found."] = "Texte non trouvé.", -- src\editor\findreplace.lua
["The API file must be located in a subdirectory of the API directory."] = "Le fichier d'API doit être placé dans un sous-répertoire du répertoire d'API.", -- src\editor\autocomplete.lua
["Toggle Break&point"] = "Créer/Supprimer un &point d'arrêt", -- src\editor\menu_project.lua
["Toggle breakpoint"] = "Créer ou supprimer un point d'arrêt", -- src\editor\menu_project.lua, src\editor\gui.lua
["Toggle breakpoint"] = "Créer ou supprimer un point d'arrêt", -- src\editor\gui.lua, src\editor\menu_project.lua
["Tr&ace"] = "&Tracer", -- src\editor\menu_project.lua
["Trace execution showing each executed line"] = "Tracer l'exécution en montrant chaque ligne de code exécutée", -- src\editor\menu_project.lua
["Unable to create directory '%s'."] = "Impossible de créer le répertoire '%s'.", -- src\editor\filetree.lua
["Unable to create file '%s'."] = "Impossible de créer le fichier '%s'.", -- src\editor\filetree.lua
["Unable to load file '%s'."] = "Impossible de charger le le fichier '%s'.", -- src\editor\commands.lua
["Unable to rename file '%s'."] = "Impossible de renommer le fichier '%s'.", -- src\editor\filetree.lua
["Unable to save file '%s': %s"] = "Impossible d'enregistrer le fichier '%s' : %s", -- src\editor\commands.lua
["Unable to stop program (pid: %d), code %d."] = "Impossible d'arrêter le programme (pid : %d), code %d.", -- src\editor\debugger.lua
["Undo last edit"] = "Annuler la dernière modification", -- src\editor\menu_edit.lua
@@ -225,12 +255,13 @@ return {
["Value"] = "Valeur", -- src\editor\debugger.lua
["View the output/console window"] = "Afficher la fenêtre de sortie/console", -- src\editor\menu_view.lua
["View the project/filetree window"] = "Afficher la fenêtre d'explorateur de projet", -- src\editor\menu_view.lua
["View the stack window"] = "Afficher la fenêtre de pile d'exécution", -- src\editor\menu_view.lua, src\editor\gui.lua
["View the watch window"] = "Afficher la fenêtre d'expressions espionnes", -- src\editor\menu_view.lua, src\editor\gui.lua
["Watch"] = "Expressions espionnes", -- src\editor\debugger.lua
["View the stack window"] = "Afficher la fenêtre de pile d'exécution", -- src\editor\gui.lua, src\editor\menu_view.lua
["View the watch window"] = "Afficher la fenêtre d'expressions espionnes", -- src\editor\gui.lua, src\editor\menu_view.lua
["Watch"] = "Expressions espionnes", -- src\editor\debugger.lua, src\editor\gui.lua
["Welcome to the interactive Lua interpreter."] = "Bienvenue dans l´interpréteur interactif Lua.", -- src\editor\shellbox.lua
["Wrap ar&ound"] = "B&oucler", -- src\editor\findreplace.lua
["You must save the program first."] = "Vous devez d'abord enregistrer le programme.", -- src\editor\commands.lua
["on line %d"] = "à la ligne %d", -- src\editor\debugger.lua, src\editor\commands.lua, src\editor\editor.lua
["traced %d instruction"] = {"%d instruction tracée", "%d instructions tracées"} -- src\editor\debugger.lua
["on line %d"] = "à la ligne %d", -- src\editor\debugger.lua, src\editor\editor.lua, src\editor\commands.lua
["traced %d instruction"] = {"%d instruction tracée", "%d instructions tracées"}, -- src\editor\debugger.lua
["unknown error"] = "erreur inconnue", -- src\editor\debugger.lua
}

View File

@@ -1,82 +1,111 @@
return {
[0] = function(c) return c == 1 and 1 or 2 end, -- plural
["%d instance"] = {"%d occorrenza", "%d occorrenze"}, -- src\editor\findreplace.lua
["%s event failed: %s"] = "L'evento %s è fallito : %s", -- src\editor\package.lua
["&About"] = "Informazioni", -- src\editor\menu_help.lua
["&Add Watch"] = "&Aggiungi Espressione di Controllo", -- src\editor\debugger.lua
["&Break"] = "Interrompi", -- src\editor\menu_project.lua
["&Close Page"] = "&Chiudi pagina", -- src\editor\menu_file.lua, src\editor\gui.lua
["&Close Page"] = "&Chiudi pagina", -- src\editor\gui.lua, src\editor\menu_file.lua
["&Community"] = "&Comunità", -- src\editor\menu_help.lua
["&Compile"] = "&Compila", -- src\editor\menu_project.lua
["&Copy"] = "&Copia", -- src\editor\editor.lua, src\editor\menu_edit.lua
["&Copy"] = "&Copia", -- src\editor\menu_edit.lua, src\editor\editor.lua
["&Default Layout"] = "Visualizzazione di &Default", -- src\editor\menu_view.lua
["&Delete Watch"] = "Elimina Espressione di Controllo", -- src\editor\debugger.lua
["&Delete"] = "Elimina", -- src\editor\filetree.lua
["&Documentation"] = "Documentazione", -- src\editor\menu_help.lua
["&Down"] = "Verso il basso", -- src\editor\findreplace.lua
["&Edit Watch"] = "Modifica Espressione di Controllo", -- src\editor\debugger.lua
["&Edit"] = "Modifica", -- src\editor\menu_edit.lua
["&File"] = "File", -- src\editor\menu_file.lua
["&Find All"] = "Trova Tutti", -- src\editor\findreplace.lua
["&Find Next"] = "Trova Successivo", -- src\editor\findreplace.lua
["&Find"] = "Ricerca", -- src\editor\menu_search.lua
["&Fold/Unfold All"] = "Apri/Chiudi tutto", -- src\editor\menu_edit.lua
["&Frequently Asked Questions"] = "Domande &Frequenti", -- src\editor\menu_help.lua
["&Getting Started Guide"] = "&Guida Introduttiva", -- src\editor\menu_help.lua
["&Goto Line"] = "Vai a riga", -- src\editor\menu_search.lua
["&Help"] = "Aiuto", -- src\editor\menu_help.lua
["&New Directory"] = "&Nuova Directory", -- src\editor\filetree.lua
["&New"] = "&Nuovo", -- src\editor\menu_file.lua
["&Open..."] = "&Apri...", -- src\editor\menu_file.lua
["&Output/Console Window"] = "Finestra di Output/Console", -- src\editor\menu_view.lua
["&Paste"] = "Incolla", -- src\editor\editor.lua, src\editor\menu_edit.lua
["&Project"] = "&Progetto", -- src\editor\menu_project.lua, src\editor\inspect.lua
["&Redo"] = "&Ripeti", -- src\editor\editor.lua, src\editor\menu_edit.lua
["&Replace"] = "Sostituisci", -- src\editor\menu_search.lua
["&Paste"] = "Incolla", -- src\editor\menu_edit.lua, src\editor\editor.lua
["&Project Page"] = "&Pagina di Progetto", -- src\editor\menu_help.lua
["&Project"] = "&Progetto", -- src\editor\inspect.lua, src\editor\menu_project.lua
["&Redo"] = "&Ripeti", -- src\editor\menu_edit.lua, src\editor\editor.lua
["&Rename"] = "&Rinomina", -- src\editor\filetree.lua
["&Replace All"] = "Sostituisci Tutti", -- src\editor\findreplace.lua
["&Replace"] = "Sostituisci", -- src\editor\findreplace.lua, src\editor\menu_search.lua
["&Run"] = "Lancia", -- src\editor\menu_project.lua
["&Save"] = "&Salva", -- src\editor\menu_file.lua, src\editor\gui.lua
["&Save"] = "&Salva", -- src\editor\gui.lua, src\editor\menu_file.lua
["&Search"] = "Ricerca", -- src\editor\menu_search.lua
["&Sort"] = "Ordina", -- src\editor\menu_search.lua
["&Sort"] = "Ordina", -- src\editor\menu_edit.lua
["&Stack Window"] = "Stack di chiamate", -- src\editor\menu_view.lua
["&Start Debugger Server"] = "Avvia Debugger Server", -- src\editor\menu_project.lua
["&Undo"] = "Annulla", -- src\editor\editor.lua, src\editor\menu_edit.lua
["&Subdirectories"] = "Sotto Directory", -- src\editor\findreplace.lua
["&Tutorials"] = "Guide", -- src\editor\menu_help.lua
["&Undo"] = "Annulla", -- src\editor\menu_edit.lua, src\editor\editor.lua
["&Up"] = "Verso l'alto", -- src\editor\findreplace.lua
["&View"] = "Visualizza", -- src\editor\menu_view.lua
["&Watch Window"] = "Finestra Espressioni di Controllo", -- src\editor\menu_view.lua
[".&bak on Replace"] = ".bak su Sostituisci", -- src\editor\findreplace.lua
["About %s"] = "Informazioni su %s", -- src\editor\menu_help.lua
["Add Watch Expression"] = "Aggiungi Espressione di Controllo", -- src\editor\editor.lua
["Add To Scratchpad"] = "Aggiungi a Scratchpad ", -- src\editor\editor.lua
["Add Watch Expression"] = "Aggiungi Espressione di Controllo", -- src\editor\editor.lua
["All files"] = "Tutti i files", -- src\editor\commands.lua
["Allow external process to start debugging"] = "Permetti a processi esterni di avviare il debug", -- src\editor\menu_project.lua
["Analyze the source code"] = "Analizza il codice", -- src\editor\inspect.lua
["Analyze"] = "Analizza", -- src\editor\inspect.lua
["Auto Complete Identifiers"] = "Autocompletamento identificatori", -- src\editor\menu_edit.lua
["Auto complete while typing"] = "Autocompletamento in linea", -- src\editor\menu_edit.lua
["Break execution at the next executed line of code"] = "Interrompi l'esecuzione alla successiva riga di codice ", -- src\editor\menu_project.lua, src\editor\gui.lua
["Break execution at the next executed line of code"] = "Interrompi l'esecuzione alla successiva riga di codice ", -- src\editor\gui.lua, src\editor\menu_project.lua
["C&lear Output Window"] = "Pulisci finestra di output", -- src\editor\menu_project.lua
["C&omment/Uncomment"] = "Commenta/Scommenta", -- src\editor\menu_edit.lua
["Can't debug the script in the active editor window."] = "Impossibile farte debug dello script nella finestra attiva", -- src\editor\debugger.lua
["Can't find file '%s' in the current project to activate for debugging. Update the project or open the file in the editor before debugging."] = "File '%s' non trovato nel progetto per attivare il debug. Modificare il progetto o apire il file prima di lanciare il debug.", -- src\editor\debugger.lua
["Can't process auto-recovery record; invalid format: %s."] = "Impossibile procedere all'auto-recovery; Formato non valido: %s.", -- src\editor\commands.lua
["Can't run the entry point script ('%s')."] = "Impossibile eseguire il punto di ingresos dello script (%s).", -- src\editor\debugger.lua
["Can't start debugger server at %s:%d: %s."] = "Impossibile lanciare il server debugger a %s:%d: %s.", -- src\editor\debugger.lua
["Can't start debugging session due to internal error '%s'."] = "Impossibile lanciare la sessione di debug: errore interno '%s'.'", -- src\editor\debugger.lua
["Can't start debugging without an opened file or with the current file not being saved ('%s')."] = "Impossibile lanciare il debug senza aver aperto un file o se il file corrente non è stato salvato ('%s').", -- src\editor\debugger.lua
["Choose ..."] = "Scegli...", -- src\editor\menu_project.lua
["Choose a project directory"] = "Scegli la directory di un progetto", -- src\editor\menu_project.lua
["Clear &Dynamic Words"] = "Elimna le &Dynamic Words", -- src\editor\menu_edit.lua
["Cancel"] = "Annulla", -- src\editor\findreplace.lua
["Cancelled by the user."] = "Annullato dall'utente", -- src\editor\findreplace.lua
["Choose..."] = "Scegli...", -- src\editor\menu_project.lua
["Choose a project directory"] = "Scegli la directory di un progetto", -- src\editor\findreplace.lua, src\editor\menu_project.lua
["Clear &Dynamic Words"] = "Elimina le &Dynamic Words", -- src\editor\menu_edit.lua
["Clear the output window before compiling or debugging"] = "Pulisci la finestra di output prima di compilare o lanciare debug", -- src\editor\menu_project.lua
["Close &Other Pages"] = "Chidi le Altre Pagine", -- src\editor\gui.lua
["Close A&ll Pages"] = "Chiudi Tutte le Pagine", -- src\editor\gui.lua
["Close the current editor window"] = "Chiude la finestra dell'edit corrente", -- src\editor\menu_file.lua
["Co&ntinue"] = "Co&ntinua", -- src\editor\menu_project.lua
["Col: %d"] = "Col: %d", -- src\editor\editor.lua
["Command Line Parameters..."] = "Parametri Riga di Comando...", -- src\editor\menu_project.lua
["Command line parameters"] = "Parametri Riga di Comando", -- src\editor\menu_project.lua
["Comment or uncomment current or selected lines"] = "Commenta o scommenta la linea corrente o selezionat", -- src\editor\menu_edit.lua
["Compilation error"] = "Errore di compilazione", -- src\editor\debugger.lua, src\editor\commands.lua
["Compilation error"] = "Errore di compilazione", -- src\editor\commands.lua, src\editor\debugger.lua
["Compilation successful; %.0f%% success rate (%d/%d)."] = "Compilazione riuscita; tasso di successo : %.0f%% (%d/%d).", -- src\editor\commands.lua
["Compile the current file"] = "Compila il file corrente", -- src\editor\menu_project.lua
["Complete &Identifier"] = "Completa l'&Identificatore", -- src\editor\menu_edit.lua
["Complete the current identifier"] = "Completa l'identificatore corrente", -- src\editor\menu_edit.lua
["Consider removing backslash from escape sequence '%s'."] = "Prova a rimuovere i backslash dalla sequenza di escape '%s'.", -- src\editor\commands.lua
["Copy Full Path"] = "Copia Path Completo", -- src\editor\filetree.lua
["Copy selected text to clipboard"] = "Copia il testo selezionato negli appunti", -- src\editor\menu_edit.lua
["Couldn't activate file '%s' for debugging; continuing without it."] = "Impossibile attivare il file '%s' per debug; si prosegue senza.", -- src\editor\debugger.lua
["Create an empty document"] = "Crea un documento vuoto", -- src\editor\menu_file.lua, src\editor\gui.lua
["Cu&t"] = "&Taglia", -- src\editor\editor.lua, src\editor\menu_edit.lua
["Create an empty document"] = "Crea un documento vuoto", -- src\editor\gui.lua, src\editor\menu_file.lua
["Cu&t"] = "&Taglia", -- src\editor\menu_edit.lua, src\editor\editor.lua
["Cut selected text to clipboard"] = "Taglia il testo selezionato e mette negli appunti", -- src\editor\menu_edit.lua
["Debugger server started at %s:%d."] = "Server Debugger iniziato %s:%s", -- src\editor\debugger.lua
["Debugging session completed (%s)."] = "Sessione di debug completata (%s).", -- src\editor\debugger.lua
["Debugging session started in '%s'."] = "Sessione di debug iniziata da '%s'.", -- src\editor\debugger.lua
["Debugging suspended at %s:%s (couldn't activate the file)."] = "Debug sospeso a %s:%s (impossibile attivare il file).", -- src\editor\debugger.lua
["Directory"] = "Directory", -- src\editor\findreplace.lua
["Do you want to delete '%s'?"] = "Vuoi eliminare '%s'?", -- src\editor\filetree.lua
["Do you want to overwrite it?"] = "Vuoi sovrascrivere '%s'?", -- src\editor\commands.lua
["Do you want to reload it?"] = "Vuoi ricaricarlo?", -- src\editor\editor.lua
["Do you want to save the changes to '%s'?"] = "Vuoi salvare le modifiche a '%s'?", -- src\editor\commands.lua
["E&xit"] = "Uscita", -- src\editor\menu_file.lua
["Enter Lua code and press Enter to run it."] = "Inserisci codice Lua e premi <Enter> per eseguirlo.", -- src\editor\shellbox.lua
["Enter command line parameters (use Cancel to clear)"] = "Inserisci i parametri riga di comando (Annulla per pulire)", -- src\editor\menu_project.lua
["Enter line number"] = "Inserisci il numero di linea", -- src\editor\menu_search.lua
["Error while loading API file: %s"] = "Errore durante il caricamento del file API: %s", -- src\editor\autocomplete.lua
["Error while loading configuration file: %s"] = "Errore nel caricamento del file di configurazione: %s", -- src\editor\style.lua
@@ -92,36 +121,49 @@ return {
["Expression"] = "Espressione", -- src\editor\debugger.lua
["File '%s' has been modified on disk."] = "Il file '%s' e' stato modificato sul disco.", -- src\editor\editor.lua
["File '%s' has more recent timestamp than restored '%s'; please review before saving."] = "Il file '%s' ha un timestamp più recente di quello ripristinato '%s'; verificare prima di salvare.", -- src\editor\commands.lua
["File '%s' no longer exists."] = "Il file '%s' non esiste piu'.", -- src\editor\editor.lua
["File '%s' no longer exists."] = "Il file '%s' non esiste piu'.", -- src\editor\menu_file.lua, src\editor\editor.lua
["File Type"] = "File Type", -- src\editor\findreplace.lua
["File already exists."] = "Il file esiste già.", -- src\editor\commands.lua
["File history"] = "Storia del file", -- src\editor\menu_file.lua
["Find &In Files"] = "Ricerca nei files", -- src\editor\menu_search.lua
["Find &Next"] = "Cerca il successivo", -- src\editor\menu_search.lua
["Find &Previous"] = "Cerca il precedente", -- src\editor\menu_search.lua
["Find In Files"] = "Ricerca nei Files", -- src\editor\findreplace.lua
["Find and replace text in files"] = "Cerca e sostituisci testo nei files", -- src\editor\menu_search.lua
["Find and replace text"] = "Cerca e sostituisci testo", -- src\editor\menu_search.lua, src\editor\gui.lua
["Find and replace text"] = "Cerca e sostituisci testo", -- src\editor\gui.lua, src\editor\menu_search.lua
["Find text in files"] = "Cerca testo nei files", -- src\editor\menu_search.lua
["Find text"] = "Cerca testo", -- src\editor\menu_search.lua, src\editor\gui.lua
["Find text"] = "Cerca testo", -- src\editor\gui.lua, src\editor\menu_search.lua
["Find the earlier text occurence"] = "Cerca la precedente occorrenza nel testo", -- src\editor\menu_search.lua
["Find the next text occurrence"] = "Cerca la successiva occorrenza nel testo", -- src\editor\menu_search.lua
["Find"] = "Ricerca", -- src\editor\findreplace.lua
["Fold or unfold all code folds"] = "Apri o chiudi tutti i blocchi di codice", -- src\editor\menu_edit.lua
["Found auto-recovery record and restored saved session."] = "Trovato punto di auto-revcovery e ripristinata la sessione salvata", -- src\editor\commands.lua
["Full &Screen"] = "Schermo pieno", -- src\editor\menu_view.lua
["Found"] = "Occorrenze trovate:", -- src\editor\findreplace.lua
["Full &Screen"] = "Schermo intero", -- src\editor\menu_view.lua
["Go To Definition"] = "Vai a Definizione", -- src\editor\editor.lua
["Go to a selected line"] = "Vai alla riga selezionata", -- src\editor\menu_search.lua
["Goto Line"] = "Vai alla riga", -- src\editor\menu_search.lua
["INS"] = "INS", -- src\editor\editor.lua
["In Files"] = "Nei Files", -- src\editor\findreplace.lua
["Jump to a function definition..."] = "Salta alla definizione della funzione...", -- src\editor\editor.lua
["Known Files"] = "Files conosciuti", -- src\editor\commands.lua
["Ln: %d"] = "Ln: %d", -- src\editor\editor.lua
["Local console"] = "Console locale", -- src\editor\shellbox.lua, src\editor\gui.lua
["Local console"] = "Console locale", -- src\editor\gui.lua, src\editor\shellbox.lua
["Lua &Interpreter"] = "&Interprete Lua", -- src\editor\menu_project.lua
["Mapped remote request for '%s' to '%s'."] = "Richiesta remota '%s' mappata su '%s'.", -- src\editor\debugger.lua
["Match &case"] = "Maiuscole/Minuscole", -- src\editor\findreplace.lua
["Match &whole word"] = "Intera parola", -- src\editor\findreplace.lua
["Mixed end-of-line encodings detected."] = "Trovata codifica Fine-Riga mista.", -- src\editor\commands.lua
["New &File"] = "Nuovo &File", -- src\editor\filetree.lua
["OVR"] = "OVR", -- src\editor\editor.lua
["Open an existing document"] = "Apri un documento esistente", -- src\editor\menu_file.lua, src\editor\gui.lua
["Open With Default Program"] = "Apri con programma predefinito", -- src\editor\filetree.lua
["Open an existing document"] = "Apri un documento esistente", -- src\editor\gui.lua, src\editor\menu_file.lua
["Open file"] = "Apri un file", -- src\editor\commands.lua
["Options"] = "Opzioni", -- src\editor\findreplace.lua
["Output (running)"] = "Output (in corso d'esecuzione)", -- src\editor\output.lua
["Output"] = "Output", -- src\editor\output.lua, src\editor\settings.lua, src\editor\gui.lua
["Output"] = "Output", -- src\editor\gui.lua, src\editor\output.lua, src\editor\settings.lua
["Paste text from the clipboard"] = "Incolla testo dagli appunti", -- src\editor\menu_edit.lua
["Preferences"] = "Preferenze", -- src\editor\menu_edit.lua
["Prepend '=' to show complex values on multiple lines."] = "Prefissa '=' per visualizzare valori complessi su piu` righe", -- src\editor\shellbox.lua
["Press cancel to abort."] = "Premi cancel per bloccare.", -- src\editor\commands.lua
["Program '%s' started in '%s' (pid: %d)."] = "Programma '%s' partito da '%s' (pid: %d).", -- src\editor\output.lua
@@ -131,57 +173,78 @@ return {
["Program stopped (pid: %d)."] = "Programma fermato (pid: %d).", -- src\editor\debugger.lua
["Program unable to run as '%s'."] = "Il programma non puo' partire '%s'.", -- src\editor\output.lua
["Project Directory"] = "Directory del Progetto", -- src\editor\menu_project.lua
["Project"] = "Progetto", -- src\editor\settings.lua, src\editor\gui.lua
["Project"] = "Progetto", -- src\editor\gui.lua, src\editor\settings.lua
["Project/&FileTree Window"] = "Progetto/Explorer", -- src\editor\menu_view.lua
["Provide command line parameters"] = "Fornire parametri riga di comando", -- src\editor\menu_project.lua
["R/O"] = "R/O", -- src\editor\editor.lua
["R/W"] = "R/W", -- src\editor\editor.lua
["Re&place In Files"] = "Sostituisci nei files", -- src\editor\menu_search.lua
["Recent Files"] = "Files recenti", -- src\editor\menu_file.lua
["Redo last edit undone"] = "Ripeti l'ultima azione annullata", -- src\editor\menu_edit.lua
["Refused a request to start a new debugging session as there is one in progress already."] = "Impossibile aprire una nuova sessione di debug in quanto ne esiste una in corso", -- src\editor\debugger.lua
["Regular &expression"] = "Regular &expression", -- src\editor\findreplace.lua
["Remote console"] = "Console remota", -- src\editor\shellbox.lua
["Rename All Instances"] = "Rinomina tutte le occorrenze", -- src\editor\editor.lua
["Replace A&ll"] = "Sostituisci Tutto", -- src\editor\findreplace.lua
["Replace"] = "Sostituisci", -- src\editor\findreplace.lua
["Replaced an invalid UTF8 character with %s."] = "Sostituito un carattere UTF8 invalido con %s.", -- src\editor\commands.lua
["Replaced"] = "Sostituiti :", -- src\editor\findreplace.lua
["Replacing"] = "Sostituzione", -- src\editor\findreplace.lua
["Reset to default layout"] = "Ritorna al default layout", -- src\editor\menu_view.lua
["Resets the dynamic word list for autocompletion"] = "Azzera la lista di dynamic words per l'autocompletamento", -- src\editor\menu_edit.lua
["Run as Scratchpad"] = "Esegui in Scratchpad (Live coding)", -- src\editor\menu_project.lua
["S&top Debugging"] = "Ferma il debugger", -- src\editor\menu_project.lua
["S&top Process"] = "Ferma il processo", -- src\editor\menu_project.lua
["Save &As..."] = "S&alva con nome...", -- src\editor\menu_file.lua, src\editor\gui.lua
["Save &As..."] = "S&alva con nome...", -- src\editor\gui.lua, src\editor\menu_file.lua
["Save A&ll"] = "Sa&lva tutto", -- src\editor\menu_file.lua
["Save Changes?"] = "Vuoi salvare le modifiche?", -- src\editor\commands.lua
["Save all open documents"] = "Salva tutti i documenti aperti", -- src\editor\menu_file.lua, src\editor\gui.lua
["Save all open documents"] = "Salva tutti i documenti aperti", -- src\editor\gui.lua, src\editor\menu_file.lua
["Save file as"] = "Salva il file con nome", -- src\editor\commands.lua
["Save file?"] = "Vuoi salvare il file?", -- src\editor\commands.lua
["Save the current document to a file with a new name"] = "Salva il documento corrente in un file con un nuovo nome", -- src\editor\menu_file.lua
["Save the current document"] = "Salva il documento corrente", -- src\editor\menu_file.lua, src\editor\gui.lua
["Save the current document"] = "Salva il documento corrente", -- src\editor\gui.lua, src\editor\menu_file.lua
["Saved auto-recover at %s."] = "Salvato auto-recover a %s.", -- src\editor\commands.lua
["Scope"] = "Direzione", -- src\editor\findreplace.lua
["Scratchpad error"] = "Errore durente Scratchpad", -- src\editor\debugger.lua
["Select &All"] = "Selezion&a Tutto", -- src\editor\editor.lua, src\editor\menu_edit.lua
["Searching for"] = "Ricerca di", -- src\editor\findreplace.lua
["Select &All"] = "Selezion&a Tutto", -- src\editor\menu_edit.lua, src\editor\editor.lua
["Select all text in the editor"] = "Seleziona tutto il testo nell'editor", -- src\editor\menu_edit.lua
["Select and Find Next"] = "Seleziona e trova successivo", -- src\editor\menu_search.lua
["Select and Find Previous"] = "Seleziona e trova precedente", -- src\editor\menu_search.lua
["Select the word under cursor and find its next occurrence"] = "Seleziona la parola e trova successivo", -- src\editor\menu_search.lua
["Select the word under cursor and find its previous occurrence"] = "Seleziona la parola e trova precedente", -- src\editor\menu_search.lua
["Set From Current File"] = "Impostato da file corrente", -- src\editor\menu_project.lua
["Set project directory from current file"] = "Definisci la directory del progeetto dal file corrente", -- src\editor\menu_project.lua, src\editor\gui.lua
["Set project directory from current file"] = "Definisci la directory del progeetto dal file corrente", -- src\editor\gui.lua, src\editor\menu_project.lua
["Set the interpreter to be used"] = "Definisci l'interprete da utilizzare", -- src\editor\menu_project.lua
["Set the project directory to be used"] = "Imposta la directory di progetto da usare", -- src\editor\menu_project.lua
["Show &Tooltip"] = "Mos&tra i consgli", -- src\editor\menu_edit.lua
["Settings: System"] = "Impostazioni: Sistema", -- src\editor\menu_edit.lua
["Settings: User"] = "Impostazioni: Utente", -- src\editor\menu_edit.lua
["Show &Tooltip"] = "Mos&tra i consigli", -- src\editor\menu_edit.lua
["Show Location"] = "Mostra posizione", -- src\editor\gui.lua, src\editor\filetree.lua
["Show tooltip for current position; place cursor after opening bracket of function"] = "Mostra i consigli per la posizione corrente; muovi il cursore dopo la parentesi o la funzione", -- src\editor\menu_edit.lua
["Sort selected lines"] = "Ordina le righe selezionate", -- src\editor\menu_search.lua
["Stack"] = "Stack", -- src\editor\debugger.lua
["Sort selected lines"] = "Ordina le righe selezionate", -- src\editor\menu_edit.lua
["Stack"] = "Stack", -- src\editor\debugger.lua, src\editor\gui.lua
["Start &Debugging"] = "Inizia il &Debug", -- src\editor\menu_project.lua
["Start debugging"] = "Inizia il Debug", -- src\editor\menu_project.lua, src\editor\gui.lua
["Start or Continue debugging"] = "Inizia o continua il debug", -- src\editor\gui.lua
["Start or continue debugging"] = "Inizia o continua il debug", -- src\editor\menu_project.lua
["Step &Into"] = "Step &Into", -- src\editor\menu_project.lua
["Step &Over"] = "Step &Over", -- src\editor\menu_project.lua
["Step O&ut"] = "Step O&ut", -- src\editor\menu_project.lua
["Step into"] = "Step into", -- src\editor\menu_project.lua, src\editor\gui.lua
["Step out of the current function"] = "Contina fino all'uscita della funzione", -- src\editor\menu_project.lua, src\editor\gui.lua
["Step over"] = "Continua senza entrare nella funzione", -- src\editor\menu_project.lua, src\editor\gui.lua
["Stop the currently running process"] = "Ferma il processo in esecuzione", -- src\editor\menu_project.lua, src\editor\gui.lua
["Step into"] = "Step into", -- src\editor\gui.lua, src\editor\menu_project.lua
["Step out of the current function"] = "Contina fino all'uscita della funzione", -- src\editor\gui.lua, src\editor\menu_project.lua
["Step over"] = "Continua senza entrare nella funzione", -- src\editor\gui.lua, src\editor\menu_project.lua
["Stop the currently running process"] = "Ferma il processo in esecuzione", -- src\editor\gui.lua, src\editor\menu_project.lua
["Switch to or from full screen mode"] = "Passa da tutto schermo a finestra", -- src\editor\menu_view.lua
["Text not found."] = "Testo non trovato.", -- src\editor\findreplace.lua
["The API file must be located in a subdirectory of the API directory."] = "Il file API deve essere presente in una sottodirectory o nella direcotory API.", -- src\editor\autocomplete.lua
["Toggle Break&point"] = "Attiva/Disattiva Break&point", -- src\editor\menu_project.lua
["Toggle breakpoint"] = "Attiva/Disattiva Breakpoint", -- src\editor\menu_project.lua, src\editor\gui.lua
["Toggle breakpoint"] = "Attiva/Disattiva Breakpoint", -- src\editor\gui.lua, src\editor\menu_project.lua
["Tr&ace"] = "Tr&ace", -- src\editor\menu_project.lua
["Trace execution showing each executed line"] = "Traccia l'esecuzione mostrando le righe eseguite", -- src\editor\menu_project.lua
["Unable to create directory '%s'."] = "Impossibile creare la directory '%s'.", -- src\editor\filetree.lua
["Unable to create file '%s'."] = "Impossibile creare il file '%s'.", -- src\editor\filetree.lua
["Unable to load file '%s'."] = "Impossibile aprire il file '%s'.", -- src\editor\commands.lua
["Unable to rename file '%s'."] = "Impossibile rinominare il file '%s'.", -- src\editor\filetree.lua
["Unable to save file '%s': %s"] = "Impossibile salvare il file '%s': %s", -- src\editor\commands.lua
["Unable to stop program (pid: %d), code %d."] = "Impossibile fermare il programma (pid: %d), code %d.", -- src\editor\debugger.lua
["Undo last edit"] = "Annulla l'ultima azione di edit", -- src\editor\menu_edit.lua
@@ -192,11 +255,13 @@ return {
["Value"] = "Valore", -- src\editor\debugger.lua
["View the output/console window"] = "Mostra la finestra di output/console", -- src\editor\menu_view.lua
["View the project/filetree window"] = "Mostra la finestra di progetto/explorer", -- src\editor\menu_view.lua
["View the stack window"] = "Mostra la finestra dello Stack", -- src\editor\menu_view.lua, src\editor\gui.lua
["View the watch window"] = "Mostra la finestra delle Espressioni di Controllo", -- src\editor\menu_view.lua, src\editor\gui.lua
["Watch"] = "Watch", -- src\editor\debugger.lua
["View the stack window"] = "Mostra la finestra dello Stack", -- src\editor\gui.lua, src\editor\menu_view.lua
["View the watch window"] = "Mostra la finestra delle Espressioni di Controllo", -- src\editor\gui.lua, src\editor\menu_view.lua
["Watch"] = "Watch", -- src\editor\debugger.lua, src\editor\gui.lua
["Welcome to the interactive Lua interpreter."] = "Benvenuti nell`interprete interattivo Lua.", -- src\editor\shellbox.lua
["Wrap ar&ound"] = "Wrap ar&ound", -- src\editor\findreplace.lua
["You must save the program first."] = "Devi prima salvare il programma", -- src\editor\commands.lua
["on line %d"] = "alla linea %d", -- src\editor\debugger.lua, src\editor\commands.lua
["traced %d instruction"] = {"tracciata %d istruzione", "%d istruzioni tracciate"} -- src\editor\debugger.lua
["on line %d"] = "alla linea %d", -- src\editor\debugger.lua, src\editor\editor.lua, src\editor\commands.lua
["traced %d instruction"] = {"tracciata %d istruzione", "%d istruzioni tracciate"}, -- src\editor\debugger.lua
["unknown error"] = "errore sconosciuto", -- src\editor\debugger.lua
}

View File

@@ -1,14 +1,18 @@
return {
[0] = function(c) c = (c-9)%100 < 9 and 9 or (c-1)%10 return c == 0 and 1 or c < 4 and 2 or 3 end, -- plural
["%d instance"] = {"%d совпадение", "%d совпадения", "%d совпадений"}, -- src\editor\findreplace.lua
["%s event failed: %s"] = nil, -- src\editor\package.lua
["&About"] = "&О программе", -- src\editor\menu_help.lua
["&Add Watch"] = "&Добавить выражение", -- src\editor\debugger.lua
["&Break"] = "Пр&ервать", -- src\editor\menu_project.lua
["&Close Page"] = "&Закрыть", -- src\editor\menu_file.lua, src\editor\gui.lua
["&Close Page"] = "&Закрыть", -- src\editor\gui.lua, src\editor\menu_file.lua
["&Community"] = nil, -- src\editor\menu_help.lua
["&Compile"] = "&Компилировать", -- src\editor\menu_project.lua
["&Copy"] = "&Копировать", -- src\editor\editor.lua, src\editor\menu_edit.lua
["&Copy"] = "&Копировать", -- src\editor\menu_edit.lua, src\editor\editor.lua
["&Default Layout"] = "Вид по &умолчанию", -- src\editor\menu_view.lua
["&Delete Watch"] = "&Удалить выражение", -- src\editor\debugger.lua
["&Delete"] = nil, -- src\editor\filetree.lua
["&Documentation"] = nil, -- src\editor\menu_help.lua
["&Down"] = "Вниз", -- src\editor\findreplace.lua
["&Edit Watch"] = "&Редактировать выражение", -- src\editor\debugger.lua
["&Edit"] = "&Правка", -- src\editor\menu_edit.lua
@@ -17,48 +21,56 @@ return {
["&Find Next"] = "Найти далее", -- src\editor\findreplace.lua
["&Find"] = "&Найти", -- src\editor\menu_search.lua
["&Fold/Unfold All"] = "Св&ернуть/развернуть все", -- src\editor\menu_edit.lua
["&Frequently Asked Questions"] = nil, -- src\editor\menu_help.lua
["&Getting Started Guide"] = nil, -- src\editor\menu_help.lua
["&Goto Line"] = "&Перейти к строке", -- src\editor\menu_search.lua
["&Help"] = "&Справка", -- src\editor\menu_help.lua
["&New Directory"] = nil, -- src\editor\filetree.lua
["&New"] = "Соз&дать", -- src\editor\menu_file.lua
["&Open..."] = "&Открыть...", -- src\editor\menu_file.lua
["&Output/Console Window"] = "Окно &вывода/консоли", -- src\editor\menu_view.lua
["&Paste"] = "В&ставить", -- src\editor\editor.lua, src\editor\menu_edit.lua
["&Project"] = "Пр&оект", -- src\editor\menu_project.lua, src\editor\inspect.lua
["&Redo"] = "Верну&ть", -- src\editor\editor.lua, src\editor\menu_edit.lua
["&Paste"] = "В&ставить", -- src\editor\menu_edit.lua, src\editor\editor.lua
["&Project Page"] = nil, -- src\editor\menu_help.lua
["&Project"] = "Пр&оект", -- src\editor\inspect.lua, src\editor\menu_project.lua
["&Redo"] = "Верну&ть", -- src\editor\menu_edit.lua, src\editor\editor.lua
["&Rename"] = nil, -- src\editor\filetree.lua
["&Replace All"] = "Заменить всe", -- src\editor\findreplace.lua
["&Replace"] = "За&менить", -- src\editor\findreplace.lua, src\editor\menu_search.lua
["&Run"] = "За&пустить", -- src\editor\menu_project.lua
["&Save"] = "&Сохранить", -- src\editor\menu_file.lua, src\editor\gui.lua
["&Save"] = "&Сохранить", -- src\editor\gui.lua, src\editor\menu_file.lua
["&Search"] = "По&иск", -- src\editor\menu_search.lua
["&Sort"] = "&Cортировать", -- src\editor\menu_search.lua
["&Sort"] = "&Cортировать", -- src\editor\menu_edit.lua
["&Stack Window"] = "Окно &стека", -- src\editor\menu_view.lua
["&Start Debugger Server"] = "Запустить сервер отла&дки", -- src\editor\menu_project.lua
["&Subdirectories"] = "В папках", -- src\editor\findreplace.lua
["&Undo"] = "&Отменить", -- src\editor\editor.lua, src\editor\menu_edit.lua
["&Tutorials"] = nil, -- src\editor\menu_help.lua
["&Undo"] = "&Отменить", -- src\editor\menu_edit.lua, src\editor\editor.lua
["&Up"] = "Вверх", -- src\editor\findreplace.lua
["&View"] = "&Вид", -- src\editor\menu_view.lua
["&Watch Window"] = "Окно &выражений", -- src\editor\menu_view.lua
[".&bak on Replace"] = ".&bak после замены", -- src\editor\findreplace.lua
["About %s"] = "О %s", -- src\editor\menu_help.lua
["Add Watch Expression"] = "Добавить выражение", -- src\editor\editor.lua
["Add To Scratchpad"] = "Добавить в черновик", -- src\editor\editor.lua
["Add Watch Expression"] = "Добавить выражение", -- src\editor\editor.lua
["All files"] = "Все файлы", -- src\editor\commands.lua
["Allow external process to start debugging"] = "Разрешить внешнему процессу начать отладку", -- src\editor\menu_project.lua
["Analyze the source code"] = "Проанализировать исходный код", -- src\editor\inspect.lua
["Analyze"] = "Анализировать", -- src\editor\inspect.lua
["Auto Complete Identifiers"] = "Автодополнение идентификаторов", -- src\editor\menu_edit.lua
["Auto complete while typing"] = "Автоматически дополнять идентификаторы при наборе", -- src\editor\menu_edit.lua
["Break execution at the next executed line of code"] = "Прервать выполнение на следующей строке", -- src\editor\menu_project.lua, src\editor\gui.lua
["Break execution at the next executed line of code"] = "Прервать выполнение на следующей строке", -- src\editor\gui.lua, src\editor\menu_project.lua
["C&lear Output Window"] = "Очистка ок&на вывода", -- src\editor\menu_project.lua
["C&omment/Uncomment"] = "Зако&мментировать/раскомментировать", -- src\editor\menu_edit.lua
["Can't debug the script in the active editor window."] = "Невозможно отладить скрипт в текущем окне редактирования.", -- src\editor\debugger.lua
["Can't find file '%s' in the current project to activate for debugging. Update the project or open the file in the editor before debugging."] = "Файл '%s', необходимый для отладки, не найден в текущем проекте. Обновите проект или откройте файл в редакторе перед началом отладки.", -- src\editor\debugger.lua
["Can't process auto-recovery record; invalid format: %s."] = "Ошибка обработки записи автоматического восстановления; неверный формат: %s.", -- src\editor\commands.lua
["Can't run the entry point script ('%s')."] = "Ошибка выполнения стартового скрипта ('%s').", -- src\editor\debugger.lua
["Can't start debugger server at %s:%d: %s."] = nil, -- src\editor\debugger.lua
["Can't start debugging session due to internal error '%s'."] = "Невозможно начать отладочную сессию из-за внутренней ошибки '%s'.", -- src\editor\debugger.lua
["Can't start debugging without an opened file or with the current file not being saved ('%s')."] = "Невозможно начать отладку без открытого файла или с несохраненным текущим файлом ('%s').", -- src\editor\debugger.lua
["Cancel"] = "Отмена", -- src\editor\findreplace.lua
["Choose ..."] = "Выбрать ...", -- src\editor\menu_project.lua
["Cancelled by the user."] = nil, -- src\editor\findreplace.lua
["Choose..."] = "Выбрать...", -- src\editor\menu_project.lua
["Choose a project directory"] = "Выберите папку проекта", -- src\editor\findreplace.lua, src\editor\menu_project.lua
["Clear &Dynamic Words"] = "Очистить &динамические слова", -- src\editor\menu_edit.lua
["Clear the output window before compiling or debugging"] = "Очистить окно вывода перед компиляцией или отладкой", -- src\editor\menu_project.lua
@@ -67,26 +79,33 @@ return {
["Close the current editor window"] = "Закрыть текущее окно редактирования", -- src\editor\menu_file.lua
["Co&ntinue"] = "Пр&одолжить", -- src\editor\menu_project.lua
["Col: %d"] = "Стб: %d", -- src\editor\editor.lua
["Command Line Parameters..."] = "Параметры командной строки...", -- src\editor\menu_project.lua
["Command line parameters"] = "Параметры командной строки", -- src\editor\menu_project.lua
["Comment or uncomment current or selected lines"] = "Закомментировать или раскомментировать текущую или выделенные строки", -- src\editor\menu_edit.lua
["Compilation error"] = "Ошибка компиляции", -- src\editor\debugger.lua, src\editor\commands.lua
["Compilation error"] = "Ошибка компиляции", -- src\editor\commands.lua, src\editor\debugger.lua
["Compilation successful; %.0f%% success rate (%d/%d)."] = "Компиляция завершена успешно; процент успеха: %.0f%% (%d/%d).", -- src\editor\commands.lua
["Compile the current file"] = "Скомпилировать текущий файл", -- src\editor\menu_project.lua
["Complete &Identifier"] = "Дополнить &идентификатор", -- src\editor\menu_edit.lua
["Complete the current identifier"] = "Дополнить текущий идентификатор", -- src\editor\menu_edit.lua
["Consider removing backslash from escape sequence '%s'."] = nil, -- src\editor\commands.lua
["Copy Full Path"] = nil, -- src\editor\filetree.lua
["Copy selected text to clipboard"] = "Скопировать выделенный текст в буфер обмена", -- src\editor\menu_edit.lua
["Couldn't activate file '%s' for debugging; continuing without it."] = "Невозможно открыть файл '%s' для отладки; выполнение будет продолжено без него.", -- src\editor\debugger.lua
["Create an empty document"] = "Создать новый документ", -- src\editor\menu_file.lua, src\editor\gui.lua
["Cu&t"] = "Вы&резать", -- src\editor\editor.lua, src\editor\menu_edit.lua
["Create an empty document"] = "Создать новый документ", -- src\editor\gui.lua, src\editor\menu_file.lua
["Cu&t"] = "Вы&резать", -- src\editor\menu_edit.lua, src\editor\editor.lua
["Cut selected text to clipboard"] = "Вырезать выделенный текст в буфер обмена", -- src\editor\menu_edit.lua
["Debugger server started at %s:%d."] = "Сервер отладки запущен на %s:%d.", -- src\editor\debugger.lua
["Debugging session completed (%s)."] = "Отладочная сессия завершена (%s).", -- src\editor\debugger.lua
["Debugging session started in '%s'."] = "Отладочная сессия запущена в '%s'.", -- src\editor\debugger.lua
["Debugging suspended at %s:%s (couldn't activate the file)."] = "Отладка остановлена на %s:%s (невозможно открыть файл).", -- src\editor\debugger.lua
["Directory"] = "Папка", -- src\editor\findreplace.lua
["Do you want to delete '%s'?"] = nil, -- src\editor\filetree.lua
["Do you want to overwrite it?"] = nil, -- src\editor\commands.lua
["Do you want to reload it?"] = "Перезагрузить его?", -- src\editor\editor.lua
["Do you want to save the changes to '%s'?"] = "Сохранить изменения в '%s'?", -- src\editor\commands.lua
["E&xit"] = "Вы&ход", -- src\editor\menu_file.lua
["Enter Lua code and press Enter to run it."] = "Введите код на Lua и нажмите Enter для выполнения.", -- src\editor\shellbox.lua
["Enter command line parameters (use Cancel to clear)"] = nil, -- src\editor\menu_project.lua
["Enter line number"] = "Введите номер строки", -- src\editor\menu_search.lua
["Error while loading API file: %s"] = "Ошибка загрузки файла определений API: %s", -- src\editor\autocomplete.lua
["Error while loading configuration file: %s"] = "Ошибка загрузки файла конфигурации: %s", -- src\editor\style.lua
@@ -102,17 +121,18 @@ return {
["Expression"] = "Выражение", -- src\editor\debugger.lua
["File '%s' has been modified on disk."] = "Файл '%s' был изменен на диске.", -- src\editor\editor.lua
["File '%s' has more recent timestamp than restored '%s'; please review before saving."] = "Файл '%s' имеет более позднее время модификации, чем восстановленный '%s'; пожалуйста просмотрите его перед сохранением.", -- src\editor\commands.lua
["File '%s' no longer exists."] = "Файл '%s' больше не существует.", -- src\editor\editor.lua, src\editor\menu_file.lua
["File '%s' no longer exists."] = "Файл '%s' больше не существует.", -- src\editor\menu_file.lua, src\editor\editor.lua
["File Type"] = "Тип файла", -- src\editor\findreplace.lua
["File already exists."] = nil, -- src\editor\commands.lua
["File history"] = "История файлов", -- src\editor\menu_file.lua
["Find &In Files"] = "Н&айти в файлах", -- src\editor\menu_search.lua
["Find &Next"] = "Найти &далее", -- src\editor\menu_search.lua
["Find &Previous"] = "Найти &ранее", -- src\editor\menu_search.lua
["Find In Files"] = "Найти в файлах", -- src\editor\findreplace.lua
["Find and replace text in files"] = "Найти и заменить текст в файлах", -- src\editor\menu_search.lua
["Find and replace text"] = "Найти и заменить текст", -- src\editor\menu_search.lua, src\editor\gui.lua
["Find and replace text"] = "Найти и заменить текст", -- src\editor\gui.lua, src\editor\menu_search.lua
["Find text in files"] = "Найти текст в файлах", -- src\editor\menu_search.lua
["Find text"] = "Найти текст", -- src\editor\menu_search.lua, src\editor\gui.lua
["Find text"] = "Найти текст", -- src\editor\gui.lua, src\editor\menu_search.lua
["Find the earlier text occurence"] = "Найти предыдущее вхождение текста", -- src\editor\menu_search.lua
["Find the next text occurrence"] = "Найти следующее вхождение текста", -- src\editor\menu_search.lua
["Find"] = "Найти", -- src\editor\findreplace.lua
@@ -120,6 +140,7 @@ return {
["Found auto-recovery record and restored saved session."] = "Найдена запись авто-восстановления и восстановлена сохраненная сессия.", -- src\editor\commands.lua
["Found"] = "Найдено", -- src\editor\findreplace.lua
["Full &Screen"] = "Во весь экр&ан", -- src\editor\menu_view.lua
["Go To Definition"] = nil, -- src\editor\editor.lua
["Go to a selected line"] = "Перейти к заданной строке", -- src\editor\menu_search.lua
["Goto Line"] = "Перейти к строке", -- src\editor\menu_search.lua
["INS"] = "ВСТ", -- src\editor\editor.lua
@@ -127,18 +148,20 @@ return {
["Jump to a function definition..."] = "Перейти к определению функции...", -- src\editor\editor.lua
["Known Files"] = "Файлы Lua", -- src\editor\commands.lua
["Ln: %d"] = "Стр: %d", -- src\editor\editor.lua
["Local console"] = "Локальная консоль", -- src\editor\shellbox.lua, src\editor\gui.lua
["Local console"] = "Локальная консоль", -- src\editor\gui.lua, src\editor\shellbox.lua
["Lua &Interpreter"] = "&Интерпретатор Lua", -- src\editor\menu_project.lua
["Mapped remote request for '%s' to '%s'."] = "Удаленный запрос для '%s' отображен на '%s'.", -- src\editor\debugger.lua
["Match &case"] = "Совпадение регистра", -- src\editor\findreplace.lua
["Match &whole word"] = "Совпадение целого слова", -- src\editor\findreplace.lua
["Mixed end-of-line encodings detected."] = "Обнаружены смешанные символы конца строки.", -- src\editor\commands.lua
["New &File"] = nil, -- src\editor\filetree.lua
["OVR"] = "ЗАМ", -- src\editor\editor.lua
["Open an existing document"] = "Открыть существующий документ", -- src\editor\menu_file.lua, src\editor\gui.lua
["Open With Default Program"] = nil, -- src\editor\filetree.lua
["Open an existing document"] = "Открыть существующий документ", -- src\editor\gui.lua, src\editor\menu_file.lua
["Open file"] = "Открыть файл", -- src\editor\commands.lua
["Options"] = "Установки", -- src\editor\findreplace.lua
["Output (running)"] = "Вывод (запущен)", -- src\editor\output.lua
["Output"] = "Вывод", -- src\editor\output.lua, src\editor\settings.lua, src\editor\gui.lua
["Output"] = "Вывод", -- src\editor\gui.lua, src\editor\output.lua, src\editor\settings.lua
["Paste text from the clipboard"] = "Вставить текст из буфера обмена", -- src\editor\menu_edit.lua
["Preferences"] = "Настройки", -- src\editor\menu_edit.lua
["Prepend '=' to show complex values on multiple lines."] = "Укажите '=' в начале выражения для отображения сложных значений на нескольких строках.", -- src\editor\shellbox.lua
@@ -150,8 +173,9 @@ return {
["Program stopped (pid: %d)."] = "Программа завершена (pid: %d).", -- src\editor\debugger.lua
["Program unable to run as '%s'."] = "Программа не может быть запущена как '%s'.", -- src\editor\output.lua
["Project Directory"] = "Папка проекта", -- src\editor\menu_project.lua
["Project"] = "Проект", -- src\editor\settings.lua, src\editor\gui.lua
["Project"] = "Проект", -- src\editor\gui.lua, src\editor\settings.lua
["Project/&FileTree Window"] = "Окно &проекта/списка файлов", -- src\editor\menu_view.lua
["Provide command line parameters"] = nil, -- src\editor\menu_project.lua
["R/O"] = "R/O", -- src\editor\editor.lua
["R/W"] = "R/W", -- src\editor\editor.lua
["Re&place In Files"] = "Замени&ть в файлах", -- src\editor\menu_search.lua
@@ -160,7 +184,8 @@ return {
["Refused a request to start a new debugging session as there is one in progress already."] = "Отказано в запросе на запуск новой отладочной сессии, поскольку одна сессия уже выполняется.", -- src\editor\debugger.lua
["Regular &expression"] = "Регулярное выражение", -- src\editor\findreplace.lua
["Remote console"] = "Удаленная консоль", -- src\editor\shellbox.lua
["Replace &All"] = "Заменить все", -- src\editor\findreplace.lua
["Rename All Instances"] = nil, -- src\editor\editor.lua
["Replace A&ll"] = "Заменить все", -- src\editor\findreplace.lua
["Replace"] = "Заменить", -- src\editor\findreplace.lua
["Replaced an invalid UTF8 character with %s."] = "Некорректный символ UTF8 заменен на %s.", -- src\editor\commands.lua
["Replaced"] = "Заменено", -- src\editor\findreplace.lua
@@ -170,47 +195,56 @@ return {
["Run as Scratchpad"] = "Запустить как черновик", -- src\editor\menu_project.lua
["S&top Debugging"] = "&Завершить отладку", -- src\editor\menu_project.lua
["S&top Process"] = "&Завершить процесс", -- src\editor\menu_project.lua
["Save &As..."] = "Сохранить &как...", -- src\editor\menu_file.lua, src\editor\gui.lua
["Save &As..."] = "Сохранить &как...", -- src\editor\gui.lua, src\editor\menu_file.lua
["Save A&ll"] = "Сохранить &все", -- src\editor\menu_file.lua
["Save Changes?"] = "Сохранить изменения?", -- src\editor\commands.lua
["Save all open documents"] = "Сохранить все открытые документы", -- src\editor\menu_file.lua, src\editor\gui.lua
["Save all open documents"] = "Сохранить все открытые документы", -- src\editor\gui.lua, src\editor\menu_file.lua
["Save file as"] = "Сохранить файл как", -- src\editor\commands.lua
["Save file?"] = "Сохранить файл?", -- src\editor\commands.lua
["Save the current document to a file with a new name"] = "Сохранить текущий документ в файл под новым именем", -- src\editor\menu_file.lua
["Save the current document"] = "Сохранить текущий документ", -- src\editor\menu_file.lua, src\editor\gui.lua
["Save the current document"] = "Сохранить текущий документ", -- src\editor\gui.lua, src\editor\menu_file.lua
["Saved auto-recover at %s."] = "Сохранено авто-восст в %s.", -- src\editor\commands.lua
["Scope"] = "Направление", -- src\editor\findreplace.lua
["Scratchpad error"] = "Ошибка в черновике", -- src\editor\debugger.lua
["Searching for"] = "Поиск", -- src\editor\findreplace.lua
["Select &All"] = "Выделить &все", -- src\editor\editor.lua, src\editor\menu_edit.lua
["Select &All"] = "Выделить &все", -- src\editor\menu_edit.lua, src\editor\editor.lua
["Select all text in the editor"] = "Выделить весь текст в редакторе", -- src\editor\menu_edit.lua
["Select and Find Next"] = "Выделить и найти далее", -- src\editor\menu_search.lua
["Select and Find Previous"] = "Выделить и найти ранее", -- src\editor\menu_search.lua
["Select the word under cursor and find its next occurrence"] = nil, -- src\editor\menu_search.lua
["Select the word under cursor and find its previous occurrence"] = nil, -- src\editor\menu_search.lua
["Set From Current File"] = "Установить по текущему файлу", -- src\editor\menu_project.lua
["Set project directory from current file"] = "Установить папку проекта по текущему файлу", -- src\editor\menu_project.lua, src\editor\gui.lua
["Set project directory from current file"] = "Установить папку проекта по текущему файлу", -- src\editor\gui.lua, src\editor\menu_project.lua
["Set the interpreter to be used"] = "Установить используемый интерпретатор", -- src\editor\menu_project.lua
["Set the project directory to be used"] = "Установить используемую папку проекта", -- src\editor\menu_project.lua
["Settings: System"] = "Установки: Системы", -- src\editor\menu_edit.lua
["Settings: User"] = "Установки: Пользователя", -- src\editor\menu_edit.lua
["Show &Tooltip"] = "Показать &подсказку", -- src\editor\menu_edit.lua
["Show Location"] = nil, -- src\editor\gui.lua, src\editor\filetree.lua
["Show tooltip for current position; place cursor after opening bracket of function"] = "Показать подсказку в текущей позиции; переместите курсор в позицию после открывающей скобки функции", -- src\editor\menu_edit.lua
["Sort selected lines"] = "Отсортировать выделенные строки", -- src\editor\menu_search.lua
["Stack"] = "Стек", -- src\editor\debugger.lua
["Sort selected lines"] = "Отсортировать выделенные строки", -- src\editor\menu_edit.lua
["Stack"] = "Стек", -- src\editor\debugger.lua, src\editor\gui.lua
["Start &Debugging"] = "Начать &отладку", -- src\editor\menu_project.lua
["Start debugging"] = "Начать отладку", -- src\editor\menu_project.lua, src\editor\gui.lua
["Start or Continue debugging"] = nil, -- src\editor\gui.lua
["Start or continue debugging"] = nil, -- src\editor\menu_project.lua
["Step &Into"] = "&Войти", -- src\editor\menu_project.lua
["Step &Over"] = "&Следующая строка", -- src\editor\menu_project.lua
["Step O&ut"] = "В&ыйти", -- src\editor\menu_project.lua
["Step into"] = "Войти в функцию", -- src\editor\menu_project.lua, src\editor\gui.lua
["Step out of the current function"] = "Выйти из текущей функции", -- src\editor\menu_project.lua, src\editor\gui.lua
["Step over"] = "Перейти на следующую строку", -- src\editor\menu_project.lua, src\editor\gui.lua
["Stop the currently running process"] = "Завершить текущий процесс", -- src\editor\menu_project.lua, src\editor\gui.lua
["Step into"] = "Войти в функцию", -- src\editor\gui.lua, src\editor\menu_project.lua
["Step out of the current function"] = "Выйти из текущей функции", -- src\editor\gui.lua, src\editor\menu_project.lua
["Step over"] = "Перейти на следующую строку", -- src\editor\gui.lua, src\editor\menu_project.lua
["Stop the currently running process"] = "Завершить текущий процесс", -- src\editor\gui.lua, src\editor\menu_project.lua
["Switch to or from full screen mode"] = "Переключить полноэкранный режим", -- src\editor\menu_view.lua
["Text not found."] = "Текст не найден.", -- src\editor\findreplace.lua
["The API file must be located in a subdirectory of the API directory."] = "Файл определений API должен быть расположен внутри папки API.", -- src\editor\autocomplete.lua
["Toggle Break&point"] = "&Точка останова", -- src\editor\menu_project.lua
["Toggle breakpoint"] = "Переключить точку останова", -- src\editor\menu_project.lua, src\editor\gui.lua
["Toggle breakpoint"] = "Переключить точку останова", -- src\editor\gui.lua, src\editor\menu_project.lua
["Tr&ace"] = "Т&рассировка", -- src\editor\menu_project.lua
["Trace execution showing each executed line"] = "Отслеживать выполнение, показывая каждую выполненную строку", -- src\editor\menu_project.lua
["Unable to create directory '%s'."] = nil, -- src\editor\filetree.lua
["Unable to create file '%s'."] = nil, -- src\editor\filetree.lua
["Unable to load file '%s'."] = "Ошибка загрузки файла '%s'.", -- src\editor\commands.lua
["Unable to rename file '%s'."] = nil, -- src\editor\filetree.lua
["Unable to save file '%s': %s"] = "Ошибка сохранения файла '%s': %s", -- src\editor\commands.lua
["Unable to stop program (pid: %d), code %d."] = "Невозможно завершить программу (pid: %d), код %d.", -- src\editor\debugger.lua
["Undo last edit"] = "Отменить последнее действие", -- src\editor\menu_edit.lua
@@ -221,12 +255,13 @@ return {
["Value"] = "Значение", -- src\editor\debugger.lua
["View the output/console window"] = "Показать окно вывода/консоли", -- src\editor\menu_view.lua
["View the project/filetree window"] = "Показать окно проекта/списка файлов", -- src\editor\menu_view.lua
["View the stack window"] = "Показать окно стека", -- src\editor\menu_view.lua, src\editor\gui.lua
["View the watch window"] = "Показать окно выражений", -- src\editor\menu_view.lua, src\editor\gui.lua
["Watch"] = "Выражение", -- src\editor\debugger.lua
["View the stack window"] = "Показать окно стека", -- src\editor\gui.lua, src\editor\menu_view.lua
["View the watch window"] = "Показать окно выражений", -- src\editor\gui.lua, src\editor\menu_view.lua
["Watch"] = "Выражение", -- src\editor\debugger.lua, src\editor\gui.lua
["Welcome to the interactive Lua interpreter."] = "Добро пожаловать в интерактивный интерпретатор Lua.", -- src\editor\shellbox.lua
["Wrap ar&ound"] = "Продолжить сначала", -- src\editor\findreplace.lua
["You must save the program first."] = "Вы должны сначала сохранить программу.", -- src\editor\commands.lua
["on line %d"] = "в строке %d", -- src\editor\debugger.lua, src\editor\commands.lua
["on line %d"] = "в строке %d", -- src\editor\debugger.lua, src\editor\editor.lua, src\editor\commands.lua
["traced %d instruction"] = {"выполнена %d инструкция", "выполнено %d инструкции", "выполнено %d инструкций"}, -- src\editor\debugger.lua
["unknown error"] = nil, -- src\editor\debugger.lua
}

View File

@@ -1,28 +1,29 @@
--[[
1. Pick a color scheme by clicking on its name:
- [Tomorrow](macro:shell(ApplyStyleConfig('cfg/tomorrow.lua','Tomorrow')))
- [TomorrowContrast](macro:shell(ApplyStyleConfig('cfg/tomorrow.lua','TomorrowContrast')))
- [TomorrowNight](macro:shell(ApplyStyleConfig('cfg/tomorrow.lua','TomorrowNight')))
- [TomorrowNightBlue](macro:shell(ApplyStyleConfig('cfg/tomorrow.lua','TomorrowNightBlue')))
- [TomorrowNightBright](macro:shell(ApplyStyleConfig('cfg/tomorrow.lua','TomorrowNightBright')))
- [TomorrowNightEighties](macro:shell(ApplyStyleConfig('cfg/tomorrow.lua','TomorrowNightEighties')))
- [Zenburn](macro:shell(ApplyStyleConfig('cfg/tomorrow.lua','Zenburn')))
- [Monokai](macro:shell(ApplyStyleConfig('cfg/tomorrow.lua','Monokai')))
- [Molokai](macro:shell(ApplyStyleConfig('cfg/tomorrow.lua','Molokai')))
- [SolarizedDark](macro:shell(ApplyStyleConfig('cfg/tomorrow.lua','SolarizedDark')))
- [SolarizedLight](macro:shell(ApplyStyleConfig('cfg/tomorrow.lua','SolarizedLight')))
- [Notepad++](macro:shell(ApplyStyleConfig('cfg/tomorrow.lua','NotepadPlusPlus')))
- [Tomorrow](macro:inline(ApplyStyleConfig('cfg/tomorrow.lua','Tomorrow'); local c = ide.config; c.stylesoutshell = c.styles; c.styles.auxwindow = c.styles.text; ReApplySpecAndStyles()))
- [TomorrowContrast](macro:inline(ApplyStyleConfig('cfg/tomorrow.lua','TomorrowContrast'); local c = ide.config; c.stylesoutshell = c.styles; c.styles.auxwindow = c.styles.text; ReApplySpecAndStyles()))
- [TomorrowNight](macro:inline(ApplyStyleConfig('cfg/tomorrow.lua','TomorrowNight'); local c = ide.config; c.stylesoutshell = c.styles; c.styles.auxwindow = c.styles.text; ReApplySpecAndStyles()))
- [TomorrowNightBlue](macro:inline(ApplyStyleConfig('cfg/tomorrow.lua','TomorrowNightBlue'); local c = ide.config; c.stylesoutshell = c.styles; c.styles.auxwindow = c.styles.text; ReApplySpecAndStyles()))
- [TomorrowNightBright](macro:inline(ApplyStyleConfig('cfg/tomorrow.lua','TomorrowNightBright'); local c = ide.config; c.stylesoutshell = c.styles; c.styles.auxwindow = c.styles.text; ReApplySpecAndStyles()))
- [TomorrowNightEighties](macro:inline(ApplyStyleConfig('cfg/tomorrow.lua','TomorrowNightEighties'); local c = ide.config; c.stylesoutshell = c.styles; c.styles.auxwindow = c.styles.text; ReApplySpecAndStyles()))
- [Zenburn](macro:inline(ApplyStyleConfig('cfg/tomorrow.lua','Zenburn'); local c = ide.config; c.stylesoutshell = c.styles; c.styles.auxwindow = c.styles.text; ReApplySpecAndStyles()))
- [Monokai](macro:inline(ApplyStyleConfig('cfg/tomorrow.lua','Monokai'); local c = ide.config; c.stylesoutshell = c.styles; c.styles.auxwindow = c.styles.text; ReApplySpecAndStyles()))
- [Molokai](macro:inline(ApplyStyleConfig('cfg/tomorrow.lua','Molokai'); local c = ide.config; c.stylesoutshell = c.styles; c.styles.auxwindow = c.styles.text; ReApplySpecAndStyles()))
- [SolarizedDark](macro:inline(ApplyStyleConfig('cfg/tomorrow.lua','SolarizedDark'); local c = ide.config; c.stylesoutshell = c.styles; c.styles.auxwindow = c.styles.text; ReApplySpecAndStyles()))
- [SolarizedLight](macro:inline(ApplyStyleConfig('cfg/tomorrow.lua','SolarizedLight'); local c = ide.config; c.stylesoutshell = c.styles; c.styles.auxwindow = c.styles.text; ReApplySpecAndStyles()))
- [Notepad++](macro:inline(ApplyStyleConfig('cfg/tomorrow.lua','NotepadPlusPlus'); local c = ide.config; c.stylesoutshell = c.styles; c.styles.auxwindow = c.styles.text; ReApplySpecAndStyles()))
- [SciTeLuaIDE](macro:inline(ApplyStyleConfig('cfg/tomorrow.lua','SciTeLuaIDE'); local c = ide.config; c.stylesoutshell = c.styles; c.styles.auxwindow = c.styles.text; ReApplySpecAndStyles()))
- [ZeroBrane Studio](macro:shell(ide.config.styles = StylesGetDefault(); ReApplySpecAndStyles()))
- [ZeroBrane Studio](macro:inline(ide.config.styles = StylesGetDefault(); local c = ide.config; c.stylesoutshell = c.styles; c.styles.auxwindow = {}; ReApplySpecAndStyles()))
2. [Apply the same scheme to Output/Console windows](macro:shell(ide.config.stylesoutshell = ide.config.styles; ReApplySpecAndStyles())).
3. Add the following code with the scheme you selected to `cfg/user.lua`.
2. Add the following code with the scheme you selected to `cfg/user.lua`.
--]]
local G = ...
styles = G.loadfile('cfg/tomorrow.lua')('TomorrowNightBlue')
stylesoutshell = styles -- also apply the same scheme to Output/Console windows
stylesoutshell = styles -- apply the same scheme to Output/Console windows
styles.auxwindow = styles.text -- apply text colors to auxiliary windows
styles.calltip = styles.text -- apply text colors to tooltips
-- code example
if false and true then func(1, 2, 3) end

View File

@@ -1,9 +1,10 @@
-- This is a file that sets color scheme based on Tomorrow format.
-- Copyright 2011-12 Paul Kulchenko, ZeroBrane LLC
-- Copyright 2011-14 Paul Kulchenko, ZeroBrane LLC
-- Tomorrow colors from https://github.com/chriskempson/tomorrow-theme
-- Zenburn colors from https://github.com/jnurmine/Zenburn/blob/master/colors/zenburn.vim (contributed by Srdjan Marković)
-- Monokai colors from http://www.monokai.nl/blog/2006/07/15/textmate-color-theme/
-- Molokai colors based on https://github.com/tomasr/molokai/blob/master/colors/molokai.vim
-- Solarized colors from https://github.com/altercation/vim-colors-solarized
local theme = ...
@@ -135,7 +136,7 @@ local colors = {
Blue = H'F92672',
Purple = H'A6E22E',
},
Molokai = { -- based on https://github.com/tomasr/molokai/blob/master/colors/molokai.vim
Molokai = {
Background = H'1B1D1E',
CurrentLine = H'293739',
Selection = H'49483E',
@@ -191,6 +192,20 @@ local colors = {
Blue = H'2123FF',
Purple = H'FFFFFF',
},
SciTeLuaIDE = { -- contributed by Jayanth Acharya
Background = H'1B1D1E',
CurrentLine = H'293739',
Selection = H'49483E',
Foreground = H'F8F8F2', -- super-light-gray (everything else)
Comment = H'00FF00', -- bright green (comments)
Red = H'F92672', -- purple (numbers)
Orange = H'AE81FF', -- lavendar?? (numbers)
Yellow = H'F8F8F2', -- light-gray
Green = H'FF8000', -- amber (string literal)
Aqua = H'808080', -- gray (operators, separators etc.)
Blue = H'0066FF', -- semi-blue (keywords)
Purple = H'A6E22E', -- light-grass-green
},
}
-- add more of the specified color (keeping all in 0-255 range)
@@ -245,12 +260,12 @@ return {
calltip = nil,
-- common special (need custom fg & bg)
calltipbg = nil,
sel = {bg = C.Selection},
caret = {fg = C.Foreground},
caretlinebg = {bg = C.CurrentLine},
fold = {fg = C.Comment, bg = C.Background, sel = mixer(C.Comment, 1, 96)},
whitespace = {fg = C.Comment, bg = C.Background},
edge = {},
indicator = {
fncall = {fg = C.Purple, st = wxstc.wxSTC_INDIC_ROUNDBOX},

View File

@@ -89,9 +89,9 @@ stylesoutshell = styles
-- to change markers used in console and output windows
styles.marker = styles.marker or {}
styles.marker.message = {ch = wxstc.wxSTC_MARK_ARROWS, {0, 0, 0}, {240, 240, 240}}
styles.marker.output = {ch = wxstc.wxSTC_MARK_BACKGROUND, {0, 0, 0}, {240, 240, 240}}
styles.marker.prompt = {ch = wxstc.wxSTC_MARK_CHARACTER+('>'):byte(), {0, 0, 0}, {240, 240, 240}}
styles.marker.message = {ch = wxstc.wxSTC_MARK_ARROWS, fg = {0, 0, 0}, bg = {240, 240, 240}}
styles.marker.output = {ch = wxstc.wxSTC_MARK_BACKGROUND, fg = {0, 0, 0}, bg = {240, 240, 240}}
styles.marker.prompt = {ch = wxstc.wxSTC_MARK_CHARACTER+('>'):byte(), fg = {0, 0, 0}, bg = {240, 240, 240}}
stylesoutshell = styles
-- to disable indicators (underlining) on function calls
@@ -103,13 +103,13 @@ styles.indicator.fncall.fg = {240,0,0}
-- to change the type of the indicator used for function calls
styles.indicator.fncall.st = wxstc.wxSTC_INDIC_PLAIN
--[[ other possible values are:
wxSTC_INDIC_PLAIN Single-line underline
wxSTC_INDIC_SQUIGGLE Squiggly underline
wxSTC_INDIC_TT Line of small T-shapes
wxSTC_INDIC_DIAGONAL Diagonal hatching
wxSTC_INDIC_STRIKE Strike-out
wxSTC_INDIC_BOX Box
wxSTC_INDIC_ROUNDBOX Rounded Box
wxSTC_INDIC_DOTS Dotted underline; wxSTC_INDIC_PLAIN Single-line underline
wxSTC_INDIC_TT Line of Tshapes; wxSTC_INDIC_SQUIGGLE Squiggly underline
wxSTC_INDIC_STRIKE Strike-out; wxSTC_INDIC_SQUIGGLELOW Squiggly underline (2 pixels)
wxSTC_INDIC_BOX Box; wxSTC_INDIC_ROUNDBOX Rounded Box
wxSTC_INDIC_DASH Dashed underline; wxSTC_INDIC_STRAIGHTBOX Box with trasparency
wxSTC_INDIC_DOTBOX Dotted rectangle; wxSTC_INDIC_DIAGONAL Diagonal hatching
wxSTC_INDIC_HIDDEN No visual effect;
--]]
-- to enable additional spec files (like spec/cpp.lua)

View File

@@ -1,18 +1,5 @@
--[[-- Copy snippets from this file to `user.lua` --]]--
--[[ Add a shortcut to generate `~` if your keyboard doesn't have one
local G = ... -- this now points to the global environment in the script
local ide, wx, TR, ID = G.ide, G.wx, G.TR, G.ID
local postinit = ide.app.postinit
ide.app.postinit = function()
if postinit then postinit() end
local menu = ide.frame.menuBar:GetMenu(ide.frame.menuBar:FindMenu(TR("&Edit")))
menu:Append(ID "tilde", "Tilde\tAlt-'")
ide.frame:Connect(ID "tilde", wx.wxEVT_COMMAND_MENU_SELECTED,
function () GetEditor():AddText("~") end)
end
--]]
--[[ Add `Evaluate in Console` option to the Edit menu
local G = ... -- this now points to the global environment in the script
local ide, wx, TR, ID = G.ide, G.wx, G.TR, G.ID
@@ -28,36 +15,6 @@ ide.app.postinit = function()
end
--]]
--[[ Add `Zoom` menu to increase/decrease/reset font in the editor
local G = ... -- this now points to the global environment in the script
local ide, wx, TR, ID = G.ide, G.wx, G.TR, G.ID
local postinit = ide.app.postinit
ide.app.postinit = function()
if postinit then postinit() end
local zoomMenu = wx.wxMenu{
{ID "zoomreset", "Zoom to 100%\tCtrl-0"},
{ID "zoomin", "Zoom In\tCtrl-+"},
{ID "zoomout", "Zoom Out\tCtrl--"},
}
local menu = ide.frame.menuBar:GetMenu(ide.frame.menuBar:FindMenu(TR("&View")))
menu:Append(ID "zoom", "Zoom", zoomMenu)
ide.frame:Connect(ID "zoomreset", wx.wxEVT_COMMAND_MENU_SELECTED,
function () GetEditor():SetZoom(1) end)
ide.frame:Connect(ID "zoomin", wx.wxEVT_COMMAND_MENU_SELECTED,
function () GetEditor():SetZoom(GetEditor():GetZoom()+1) end)
ide.frame:Connect(ID "zoomout", wx.wxEVT_COMMAND_MENU_SELECTED,
function () GetEditor():SetZoom(GetEditor():GetZoom()-1) end)
-- only enable if there is an editor
for _, m in G.ipairs({"zoomreset", "zoomin", "zoomout"}) do
ide.frame:Connect(ID(m), wx.wxEVT_UPDATE_UI,
function (event) event:Enable(GetEditor() ~= nil) end)
end
end
--]]
--[[ An example of how individual keywords can be styled
local G = ... -- this now points to the global environment in the script
local luaspec = G.ide.specs['lua']

66
interpreters/busted.lua Normal file
View File

@@ -0,0 +1,66 @@
-- Copyright 2011-13 Paul Kulchenko, ZeroBrane LLC
local busted
local win = ide.osname == "Windows"
return {
name = "Busted",
description = "Busted Lua testing",
api = {"baselib"},
frun = function(self,wfilename,rundebug)
busted = busted or ide.config.path.busted -- check if the path is configured
if not busted then
local sep = win and ';' or ':'
local path = (os.getenv('PATH') or '')..sep
..(os.getenv('HOME') and os.getenv('HOME') .. '/bin' or '')
local paths = {}
for p in path:gmatch("[^"..sep.."]+") do
busted = busted or GetFullPathIfExists(p, win and 'busted.exe' or 'busted')
table.insert(paths, p)
end
if not busted then
DisplayOutput("Can't find busted executable in any of the folders in PATH: "
..table.concat(paths, ", ").."\n")
return
end
end
local file
if rundebug then
-- start running the application right away
DebuggerAttachDefault({runstart = ide.config.debugger.runonstart == true})
local code = (
[=[xpcall(function() io.stdout:setvbuf('no')
require('mobdebug').start(); dofile [[%s]]
end, function(err) print(debug.traceback(err)) end)]=])
:format(wfilename:GetFullPath())
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()
local options = ide.config.busted and ide.config.busted.options
or "--output=TAP"
local cmd = ('"%s" %s "%s"'):format(busted, options, 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,
}

View File

@@ -51,14 +51,38 @@ return {
end
end
local filepath = wfilename:GetFullPath()
if rundebug then
DebuggerAttachDefault({runstart = ide.config.debugger.runonstart == true})
end
local cmd = ('"%s" "%s"'):format(gslshell, wfilename:GetFullPath())
local tmpfile = wx.wxFileName()
tmpfile:AssignTempFileName(".")
filepath = tmpfile:GetFullPath()
local f = io.open(filepath, "w")
if not f then
DisplayOutput("Can't open temporary file '"..filepath.."' for writing\n")
return
end
f:write(rundebug)
f:close()
else
-- 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
end
local params = ide.config.arg.any or ide.config.arg.gslshell
local code = ([[-e "io.stdout:setvbuf('no')" "%s"]]):format(filepath)
local cmd = '"'..gslshell..'" '..code..(params and " "..params 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)
function() ide.debugger.pid = nil if rundebug then wx.wxRemoveFile(filepath) end end)
end,
fprojdir = function(self,wfilename)
return wfilename:GetPath(wx.wxPATH_GET_VOLUME)
@@ -70,4 +94,6 @@ return {
fattachdebug = function(self) DebuggerAttachDefault() end,
skipcompile = true,
unhideanywindow = true,
scratchextloop = false,
takeparameters = true,
}

View File

@@ -1,3 +1,6 @@
-- add `lfw = {chdirtofile = true}` to the configuration file to set file
-- directory as the current one when Running or Debugging LuaForWindows projects.
if ide.osname ~= "Windows" or not os.getenv("LUA_DEV") then return end
local exe
@@ -54,7 +57,8 @@ return {
return wfilename:GetPath(wx.wxPATH_GET_VOLUME)
end,
fworkdir = function (self,wfilename)
return wfilename:GetPath(wx.wxPATH_GET_VOLUME)
return (not ide.config.lfw or ide.config.lfw.chdirtofile ~= true)
and ide.config.path.projectdir or wfilename:GetPath(wx.wxPATH_GET_VOLUME)
end,
hasdebugger = true,
fattachdebug = function(self) DebuggerAttachDefault() end,

View File

@@ -42,8 +42,9 @@ return {
DebuggerAttachDefault({runstart = ide.config.debugger.runonstart == true})
end
local cmd = ('"%s" "%s"%s'):format(love2d,
self:fworkdir(wfilename), rundebug and ' -debug' or '')
local params = ide.config.arg.any or ide.config.arg.love2d
local cmd = ('"%s" "%s"%s%s'):format(love2d, self:fworkdir(wfilename),
params and " "..params or "", 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)
@@ -57,4 +58,5 @@ return {
hasdebugger = true,
fattachdebug = function(self) DebuggerAttachDefault() end,
scratchextloop = true,
takeparameters = true,
}

View File

@@ -3,6 +3,7 @@ function MakeLuaInterpreter(version, name)
local exe
local function exePath(self, version)
local version = tostring(version):gsub('%.','')
local mainpath = ide.editorFilename:gsub("[^/\\]+$","")
local macExe = mainpath..([[bin/lua.app/Contents/MacOS/lua%s]]):format(version)
return ide.config.path['lua'..version]
@@ -15,12 +16,24 @@ return {
name = ("Lua%s"):format(name or version or ""),
description = ("Lua%s interpreter with debugger"):format(name or version or ""),
api = {"wxwidgets","baselib"},
luaversion = version or '5.1',
fexepath = exePath,
frun = function(self,wfilename,rundebug)
exe = exe or self:fexepath(version or "")
local filepath = wfilename:GetFullPath()
if rundebug then
DebuggerAttachDefault({runstart = ide.config.debugger.runonstart == true})
local tmpfile = wx.wxFileName()
tmpfile:AssignTempFileName(".")
filepath = tmpfile:GetFullPath()
local f = io.open(filepath, "w")
if not f then
DisplayOutput("Can't open temporary file '"..filepath.."' for writing\n")
return
end
f:write(rundebug)
f:close()
else
-- if running on Windows and can't open the file, this may mean that
-- the file path includes unicode characters that need special handling
@@ -32,22 +45,21 @@ return {
filepath = winapi.short_path(filepath)
end
end
local code = rundebug
and ([[-e "io.stdout:setvbuf('no'); %s"]]):format(rundebug)
or ([[-e "io.stdout:setvbuf('no')" "%s"]]):format(filepath)
local cmd = '"'..exe..'" '..code
local params = ide.config.arg.any or ide.config.arg.lua
local code = ([[-e "io.stdout:setvbuf('no')" "%s"]]):format(filepath)
local cmd = '"'..exe..'" '..code..(params and " "..params or "")
-- modify CPATH to work with other Lua versions
local clibs = ('/clibs%s/'):format(version and tostring(version):gsub('%.','') or '')
local _, cpath = wx.wxGetEnv("LUA_CPATH")
if version and cpath and not cpath:find('clibs'..version, 1, true) then
wx.wxSetEnv("LUA_CPATH", cpath:gsub('clibs', 'clibs'..version))
end
if version and cpath and not cpath:find(clibs, 1, true) then
wx.wxSetEnv("LUA_CPATH", cpath:gsub('/clibs/', clibs)) end
-- CommandLineRun(cmd,wdir,tooutput,nohide,stringcallback,uid,endcallback)
local pid = CommandLineRun(cmd,self:fworkdir(wfilename),true,false,nil,nil,
function() ide.debugger.pid = nil end)
function() ide.debugger.pid = nil if rundebug then wx.wxRemoveFile(filepath) end end)
if version then wx.wxSetEnv("LUA_CPATH", cpath) end
if version and cpath then wx.wxSetEnv("LUA_CPATH", cpath) end
return pid
end,
fprojdir = function(self,wfilename)
@@ -60,6 +72,7 @@ return {
fattachdebug = function(self) DebuggerAttachDefault() end,
scratchextloop = false,
unhideanywindow = true,
takeparameters = true,
}
end

View File

@@ -1,2 +1,2 @@
dofile 'interpreters/luabase.lua'
return MakeLuaInterpreter('52', ' 5.2')
return MakeLuaInterpreter(5.2, ' 5.2')

View File

@@ -2,94 +2,77 @@
return {
name = "Luxinia2",
description = "Luxinia2",
api = {"baselib","glfw","glewgl","assimp20","luxmath","luxgfx","luxscene","luajit2",},
finitclient = function(self)
if (not CommandLineRunning(self:fuid(wfilename))) then return end
if not ide.config.path.luxinia2 then wx.wxMessageBox("Please define 'path.luxinia2' in your cfg/user.lua (see estrela.lua for examples)"); return end
local init = dofile(ide.config.path.luxinia2.."/../comserver/client.lua")
local fenv = {}
setmetatable(fenv,{__index = _G})
fenv.print = function(...) DisplayOutput(...); DisplayOutput("\n"); end
setfenv(init,fenv)
local client = init()
self.fclient = client
return client
end,
api = {"baselib","glfw","glewgl","assimp20","luxmath","luxscene","luajit2",},
frun = function(self,wfilename,rundebug)
local luxdir = ide.config.path.luxinia2
local projdir = ide.config.path.projectdir
assert(projdir and projdir:len()>0,"no project directory")
local basedir = luxdir
local startfile = projdir.."/main.lua"
local startargs = " -e "..startfile
if (CommandLineRunning(self:fuid(wfilename))) then
if (not self.fclient) then
self:finitclient()
end
-- try to communicate with server
self.fclient("dofile([["..wfilename:GetFullPath().."]])")
local editorDir = string.gsub(ide.editorFilename:gsub("[^/\\]+$",""),"\\","/")
local luxDir = ide.config.path.luxinia2 or os.getenv("LUXINIA2")
local scratchpad = rundebug and rundebug:match("scratchpad")
local filename = wfilename:GetFullName()
if (wx.wxFileName(luxDir):IsRelative()) then
luxDir = editorDir..luxDir
end
if (not luxDir) then
DisplayOutputLn("Error: path.luxinia2 not set in config or LUXINIA2 environment missing")
return
end
local exe = luxDir.."/luajit.exe"
local wdir = self:fworkdir(wfilename)
if (wx.wxFileExists(wdir.."/main.lua")) then
wfilename = wx.wxFileName(wdir.."/main.lua")
DisplayOutputLn("luxinia2: using project main.lua")
end
if (scratchpad and filename ~= wfilename:GetFullName()) then
DisplayOutputLn("luxinia2: scratchpad currently requires starting with main.lua (if exists)\n However, do not edit its content, but add other files to scratchpad.\n In general you should start with the file that hosts the initialization\n and main loop, then edit other files.")
return
end
self.fclient = nil
local fname = wfilename:GetFullName()
local args = (fname and (" -f "..fname) or "")
if rundebug then
DebuggerAttachDefault({
basedir=basedir,
startfile=startfile,
run=true, noshell=true,}
)
local editorDir = string.gsub(ide.editorFilename:gsub("[^/\\]+$",""),"\\","/")
script = ""..
"package.path=package.path..';"..editorDir.."lualibs/?/?.lua';"..
"io.stdout:setvbuf('no'); require('mobdebug').start('" .. ide.debugger.hostname.."',"..ide.debugger.portnumber..")"
args = args..' -es "'..script..'"'..startargs
else
args = " -s "..args..startargs
local pid, proc
if (CommandLineRunning(self:fuid(wfilename))) then
-- kill process
wx.wxProcess.Kill(pid)
end
local jitargs = ide.config.luxinia2jitargs
jitargs = jitargs or ""
local cmd = 'luajit.exe '..jitargs..' ../main.lua '..args
local pid = CommandLineRun(cmd,ide.config.path.luxinia2,true,true,nil,self:fuid(wfilename),
function()
ShellSupportRemote(nil)
if (rundebug) then
DebuggerStop()
end
end)
if(not pid) then return end
if not rundebug then
local client = self:finitclient()
ShellSupportRemote(client,self:fuid(wfilename))
pid = nil
local filename = wfilename:GetFullName()
local args = [[ -e "io.stdout:setvbuf('no');" ]]..(ide.config.luxinia2args or "")
-- ensure luxinia's libs come first, to allow 32- and 64-bit debugging
-- or running from zbstudio in general, as zbs modifies LUA_CPATH
args = args..' -e "dofile [['..luxDir..'/../setup_package_paths.lua]];"'
if rundebug then
DebuggerAttachDefault({ runstart = ide.config.debugger.runonstart == true,
startwith = wfilename:GetFullPath(),
})
if (scratchpad) then
args = args..' -e "_IS_SCRATCH = true;"'
else
args = args..' -e "_IS_DEBUG = true;"'
end
end
args = args..(rundebug
and ([[ -e "%s"]]):format(rundebug)
or ([[ "%s"]]):format(filename))
local cmd = '"'..exe..'" '..args
local pid = CommandLineRun(cmd,wdir,true,true,nil,self:fuid(wfilename),
function() ide.debugger.pid = nil end)
return pid
end,
fuid = function(self,wfilename) return "luxinia2 "..(ide.config.path.projectdir or "") end,
fuid = function(self,wfilename) return "luxinia2: luajit "..wfilename:GetFullName() end,
fprojdir = function(self,wfilename)
local path = GetPathWithSep(wfilename)
filepath = wx.wxFileName(path)
while ((not wx.wxFileExists(path.."main.lua")) and (filepath:GetDirCount() > 0)) do
filepath:RemoveDir(filepath:GetDirCount()-1)
path = GetPathWithSep(filepath)
end
return path:sub(0,-2)
return wfilename:GetPath(wx.wxPATH_GET_VOLUME)
end,
fworkdir = function (self,wfilename)
return ide.config.path.projectdir or wfilename:GetPath(wx.wxPATH_GET_VOLUME)
end,
hasdebugger = true,
fattachdebug = function(self) DebuggerAttachDefault() end,
scratchextloop = true,
}

View File

@@ -18,7 +18,8 @@ return {
win and ([[C:\Marmalade]]..sep..[[D:\Marmalade]]..sep..
[[C:\Program Files\Marmalade]]..sep..[[D:\Program Files\Marmalade]]..sep..
[[C:\Program Files (x86)\Marmalade]]..sep..[[D:\Program Files (x86)\Marmalade]]..sep)
or mac and ([[/Developer/Marmalade]]..sep)
or mac and ([[/Applications/Marmalade.app/Contents]]..sep..
[[/Developer/Marmalade]]..sep)
or ''
-- Marmalade can be installed in a folder with version number or without
-- so it may be c:\Marmalade\s3e\... or c:\Marmalade\6.2\s3e\...
@@ -29,6 +30,8 @@ return {
if GetFullPathIfExists(candidate, exe) then table.insert(candidates, candidate) end
if GetFullPathIfExists(candidate.."/s3e", exe) then table.insert(candidates, candidate.."/s3e") end
end
-- stop on Mac if found something in /Applications (7.0+)
if mac and #candidates > 0 then break end
end
-- multiple candidates may be present, so sort and use the latest.
-- only happens if multiple versions are installed and S3E_DIR is not set.
@@ -43,6 +46,8 @@ return {
end
end
if not s3e then s3e = quick:gsub(exe, '') end
local projdir = self:fworkdir(wfilename)
local file = GetFullPathIfExists(projdir, 'main.lua')
if not file then

112
lualibs/dist/config.lua vendored Normal file
View File

@@ -0,0 +1,112 @@
-- Luadist configuration
module ("dist.config", package.seeall)
local sys = require "dist.sys"
local utils = require "dist.utils"
local win = (os.getenv('WINDIR') or (os.getenv('OS') or ''):match('[Ww]indows'))
and not (os.getenv('OSTYPE') or ''):match('cygwin') -- exclude cygwin
-- System information ------------------------------------------------
version = "0.2.7" -- Current LuaDist version
-- set initial architecture as it's important for path separators
arch = win and "Windows" or "Linux" -- Host architecture
type = "x86" -- Host type
-- Directories -------------------------------------------------------
root_dir = os.getenv("DIST_ROOT") or utils.get_luadist_location() or sys.path_separator()
temp_dir = "tmp"
cache_dir = sys.make_path(temp_dir, "cache")
distinfos_dir = sys.make_path("share", "luadist-git", "dists")
test_dir = sys.make_path("share", "luadist-git", "test")
-- Files -------------------------------------------------------------
manifest_file = sys.make_path(cache_dir, ".gitmodules")
dep_cache_file = sys.make_path(cache_dir, ".depcache")
log_file = sys.make_path(temp_dir, "luadist.log")
cache_file = ""
-- Repositories ------------------------------------------------------
repos = {
"git://github.com/LuaDist/Repository.git",
}
upload_url = "git@github.com:LuaDist" -- must not contain trailing '/'
-- Settings ----------------------------------------------------------
debug = false -- Use debug mode.
verbose = false -- Print verbose output.
simulate = false -- Only simulate installation of packages.
binary = true -- Use binary version of modules.
source = true -- Use source version of modules.
test = false -- Run CTest before install.
cache = true -- Use cache.
cache_timeout = 3 * 60 * 60 -- Cache timeout in seconds.
dep_cache = true -- Use cache for dependency information (tree functionality).
-- Components (of modules) that will be installed.
components = {
"Runtime", "Library", "Header", "Data", "Documentation", "Example", "Test", "Other", "Unspecified"
}
-- Available log levels are: DEBUG, INFO, WARN, ERROR, FATAL (see dist.logger for more information).
print_log_level = "WARN" -- Minimum level for log messages to be printed (nil to disable).
write_log_level = "INFO" -- Minimum level for log messages to be logged (nil to disable).
-- CMake variables ---------------------------------------------------
variables = {
--- Install defaults
INSTALL_BIN = "bin",
INSTALL_LIB = "lib",
INSTALL_INC = "include",
INSTALL_ETC = "etc",
INSTALL_LMOD = "lib/lua",
INSTALL_CMOD = "lib/lua",
--- LuaDist specific variables
DIST_VERSION = version,
DIST_ARCH = arch,
DIST_TYPE = type,
-- CMake specific setup
CMAKE_GENERATOR = win and "MinGW Makefiles" or "Unix Makefiles",
CMAKE_BUILD_TYPE = "MinSizeRel",
-- RPath functionality
CMAKE_SKIP_BUILD_RPATH = "FALSE",
CMAKE_BUILD_WITH_INSTALL_RPATH = "FALSE",
CMAKE_INSTALL_RPATH = "$ORIGIN/../lib",
CMAKE_INSTALL_RPATH_USE_LINK_PATH = "TRUE",
CMAKE_INSTALL_NAME_DIR = "@executable_path/../lib",
-- OSX specific
CMAKE_OSX_ARCHITECTURES = "",
}
-- Building ----------------------------------------------------------
cmake = "cmake"
ctest = "ctest"
cache_command = cmake .. " -C cache.cmake"
build_command = cmake .. " --build . --clean-first"
install_component_command = " -DCOMPONENT=#COMPONENT# -P cmake_install.cmake"
test_command = ctest .. " -V ."
strip_option = " -DCMAKE_INSTALL_DO_STRIP=true"
cache_debug_options = "-DCMAKE_VERBOSE_MAKEFILE=true -DCMAKE_BUILD_TYPE=Debug"
build_debug_options = ""
-- Add -j option to make in case of unix makefiles to speed up builds
if (variables.CMAKE_GENERATOR == "Unix Makefiles") then
build_command = build_command .. " -- -j6"
end
-- Add -j option to make in case of MinGW makefiles to speed up builds
if (variables.CMAKE_GENERATOR == "MinGW Makefiles") then
build_command = "set SHELL=cmd.exe && " .. build_command .. " -- -j"
end

271
lualibs/dist/constraints.lua vendored Normal file
View File

@@ -0,0 +1,271 @@
-- Note: the code of this module is borrowed from the original LuaDist project
--- LuaDist version constraints functions
-- Peter Drahoš, LuaDist Project, 2010
-- Original Code borrowed from LuaRocks Project
--- Version constraints handling functions.
-- Dependencies are represented in LuaDist through strings with
-- a dist name followed by a comma-separated list of constraints.
-- Each constraint consists of an operator and a version number.
-- In this string format, version numbers are represented as
-- naturally as possible, like they are used by upstream projects
-- (e.g. "2.0beta3"). Internally, LuaDist converts them to a purely
-- numeric representation, allowing comparison following some
-- "common sense" heuristics. The precise specification of the
-- comparison criteria is the source code of this module, but the
-- test/test_deps.lua file included with LuaDist provides some
-- insights on what these criteria are.
module ("dist.constraints", package.seeall)
local operators = {
["=="] = "==",
["~="] = "~=",
[">"] = ">",
["<"] = "<",
[">="] = ">=",
["<="] = "<=",
["~>"] = "~>",
-- plus some convenience translations
[""] = "==",
["-"] = "==",
["="] = "==",
["!="] = "~="
}
local deltas = {
scm = -100,
rc = -1000,
pre = -10000,
beta = -100000,
alpha = -1000000,
work = -10000000,
}
local version_mt = {
--- Equality comparison for versions.
-- All version numbers must be equal.
-- If both versions have revision numbers, they must be equal;
-- otherwise the revision number is ignored.
-- @param v1 table: version table to compare.
-- @param v2 table: version table to compare.
-- @return boolean: true if they are considered equivalent.
__eq = function(v1, v2)
if #v1 ~= #v2 then
return false
end
for i = 1, #v1 do
if v1[i] ~= v2[i] then
return false
end
end
if v1.revision and v2.revision then
return (v1.revision == v2.revision)
end
return true
end,
--- Size comparison for versions.
-- All version numbers are compared.
-- If both versions have revision numbers, they are compared;
-- otherwise the revision number is ignored.
-- @param v1 table: version table to compare.
-- @param v2 table: version table to compare.
-- @return boolean: true if v1 is considered lower than v2.
__lt = function(v1, v2)
for i = 1, math.max(#v1, #v2) do
local v1i, v2i = v1[i] or 0, v2[i] or 0
if v1i ~= v2i then
return (v1i < v2i)
end
end
if v1.revision and v2.revision then
return (v1.revision < v2.revision)
end
return false
end
}
local version_cache = {}
setmetatable(version_cache, {
__mode = "kv"
})
--- Parse a version string, converting to table format.
-- A version table contains all components of the version string
-- converted to numeric format, stored in the array part of the table.
-- If the version contains a revision, it is stored numerically
-- in the 'revision' field. The original string representation of
-- the string is preserved in the 'string' field.
-- Returned version tables use a metatable
-- allowing later comparison through relational operators.
-- @param vstring string: A version number in string format.
-- @return table or nil: A version table or nil
-- if the input string contains invalid characters.
function parseVersion(vstring)
if not vstring then return nil end
assert(type(vstring) == "string")
local cached = version_cache[vstring]
if cached then
return cached
end
local version = {}
local i = 1
local function add_token(number)
version[i] = version[i] and version[i] + number/100000 or number
i = i + 1
end
-- trim leading and trailing spaces
vstring = vstring:match("^%s*(.*)%s*$")
version.string = vstring
-- store revision separately if any
local main, revision = vstring:match("(.*)%-(%d+)$")
if revision then
vstring = main
version.revision = tonumber(revision)
end
while #vstring > 0 do
-- extract a number
local token, rest = vstring:match("^(%d+)[%.%-%_]*(.*)")
if token then
add_token(tonumber(token))
else
-- extract a word
token, rest = vstring:match("^(%a+)[%.%-%_]*(.*)")
if not token then
return nil
end
local last = #version
version[i] = deltas[token] or (token:byte() / 1000)
end
vstring = rest
end
setmetatable(version, version_mt)
version_cache[vstring] = version
return version
end
--- Utility function to compare version numbers given as strings.
-- @param a string: one version.
-- @param b string: another version.
-- @return boolean: True if a > b.
function compareVersions(a, b)
return parseVersion(a) > parseVersion(b)
end
--- Consumes a constraint from a string, converting it to table format.
-- For example, a string ">= 1.0, > 2.0" is converted to a table in the
-- format {op = ">=", version={1,0}} and the rest, "> 2.0", is returned
-- back to the caller.
-- @param input string: A list of constraints in string format.
-- @return (table, string) or nil: A table representing the same
-- constraints and the string with the unused input, or nil if the
-- input string is invalid.
local function parseConstraint(input)
assert(type(input) == "string")
local op, version, rest = input:match("^([<>=~!]*)%s*([%w%.%_%-]+)[%s,]*(.*)")
op = operators[op]
version = parseVersion(version)
if not op or not version then return nil end
return { op = op, version = version }, rest
end
--- Convert a list of constraints from string to table format.
-- For example, a string ">= 1.0, < 2.0" is converted to a table in the format
-- {{op = ">=", version={1,0}}, {op = "<", version={2,0}}}.
-- Version tables use a metatable allowing later comparison through
-- relational operators.
-- @param input string: A list of constraints in string format.
-- @return table or nil: A table representing the same constraints,
-- or nil if the input string is invalid.
function parseConstraints(input)
assert(type(input) == "string")
local constraints, constraint = {}, nil
while #input > 0 do
constraint, input = parseConstraint(input)
if constraint then
table.insert(constraints, constraint)
else
return nil
end
end
return constraints
end
--- A more lenient check for equivalence between versions.
-- This returns true if the requested components of a version
-- match and ignore the ones that were not given. For example,
-- when requesting "2", then "2", "2.1", "2.3.5-9"... all match.
-- When requesting "2.1", then "2.1", "2.1.3" match, but "2.2"
-- doesn't.
-- @param version string or table: Version to be tested; may be
-- in string format or already parsed into a table.
-- @param requested string or table: Version requested; may be
-- in string format or already parsed into a table.
-- @return boolean: True if the tested version matches the requested
-- version, false otherwise.
local function partialMatch(version, requested)
assert(type(version) == "string" or type(version) == "table")
assert(type(requested) == "string" or type(version) == "table")
if type(version) ~= "table" then version = parseVersion(version) end
if type(requested) ~= "table" then requested = parseVersion(requested) end
if not version or not requested then return false end
for i = 1, #requested do
if requested[i] ~= version[i] then return false end
end
if requested.revision then
return requested.revision == version.revision
end
return true
end
--- Check if a version satisfies a set of constraints.
-- @param version table: A version in table format
-- @param constraints table: An array of constraints in table format.
-- @return boolean: True if version satisfies all constraints,
-- false otherwise.
function matchConstraints(version, constraints)
assert(type(version) == "table")
assert(type(constraints) == "table")
local ok = true
setmetatable(version, version_mt)
for _, constr in pairs(constraints) do
local constr_version = constr.version
setmetatable(constr.version, version_mt)
if constr.op == "==" then ok = version == constr_version
elseif constr.op == "~=" then ok = version ~= constr_version
elseif constr.op == ">" then ok = version > constr_version
elseif constr.op == "<" then ok = version < constr_version
elseif constr.op == ">=" then ok = version >= constr_version
elseif constr.op == "<=" then ok = version <= constr_version
elseif constr.op == "~>" then ok = partialMatch(version, constr_version)
end
if not ok then break end
end
return ok
end
--- Check if a version string is satisfied by a constraint string.
-- @param version string: A version in string format
-- @param constraints string: Constraints in string format.
-- @return boolean: True if version satisfies all constraints,
-- false otherwise.
function constraint_satisfied(version, constraints)
local const = parseConstraints(constraints)
local ver = parseVersion(version)
if const and ver then
return matchConstraints(ver, const)
end
return nil, "Error parsing versions."
end

770
lualibs/dist/depends.lua vendored Normal file
View File

@@ -0,0 +1,770 @@
-- Utility functions for dependencies
module ("dist.depends", package.seeall)
local cfg = require "dist.config"
local mf = require "dist.manifest"
local sys = require "dist.sys"
local const = require "dist.constraints"
local utils = require "dist.utils"
local package = require "dist.package"
-- Return all packages with specified names from manifest.
-- Names can also contain version constraint (e.g. 'copas>=1.2.3', 'saci-1.0' etc.).
function find_packages(package_names, manifest)
if type(package_names) == "string" then package_names = {package_names} end
manifest = manifest or mf.get_manifest()
assert(type(package_names) == "table", "depends.find_packages: Argument 'package_names' is not a table or string.")
assert(type(manifest) == "table", "depends.find_packages: Argument 'manifest' is not a table.")
local packages_found = {}
-- find matching packages in manifest
for _, pkg_to_find in pairs(package_names) do
local pkg_name, pkg_constraint = split_name_constraint(pkg_to_find)
pkg_name = utils.escape_magic(pkg_name):gsub("%%%*",".*")
for _, repo_pkg in pairs(manifest) do
if string.match(repo_pkg.name, "^" .. pkg_name .. "$") and (not pkg_constraint or satisfies_constraint(repo_pkg.version, pkg_constraint)) then
table.insert(packages_found, repo_pkg)
end
end
end
return packages_found
end
-- Return manifest consisting of packages installed in specified deploy_dir directory
function get_installed(deploy_dir)
deploy_dir = deploy_dir or cfg.root_dir
assert(type(deploy_dir) == "string", "depends.get_installed: Argument 'deploy_dir' is not a string.")
deploy_dir = sys.abs_path(deploy_dir)
local distinfos_path = sys.make_path(deploy_dir, cfg.distinfos_dir)
local manifest = {}
if not sys.is_dir(distinfos_path) then return {} end
-- from all directories of packages installed in deploy_dir
for dir in sys.get_directory(distinfos_path) do
if dir ~= "." and dir ~= ".." and sys.is_dir(sys.make_path(distinfos_path, dir)) then
local pkg_dist_dir = sys.make_path(distinfos_path, dir)
-- load the dist.info file
for file in sys.get_directory(pkg_dist_dir) do
local pkg_dist_file = sys.make_path(pkg_dist_dir, file)
if sys.is_file(pkg_dist_file) then
table.insert(manifest, mf.load_distinfo(pkg_dist_file))
end
end
end
end
return manifest
end
-- If 'pkg.selected' == true then returns 'selected' else 'installed'.
-- Used in error messages.
local function selected_or_installed(pkg)
assert(type(pkg) == "table", "depends.selected_or_installed: Argument 'pkg' is not a table.")
if pkg.selected == true then
return "selected"
else
return "installed"
end
end
-- Return whether the 'package_name' is installed according to the the manifest 'installed_pkgs'
-- If optional 'version_wanted' constraint is specified, then installed packages must
-- also satisfy specified version constraint.
-- If package is installed but doesn't satisfy version constraint, error message
-- is returned as the second value.
function is_installed(package_name, installed_pkgs, version_wanted)
assert(type(package_name) == "string", "depends.is_installed: Argument 'package_name' is not a string.")
assert(type(installed_pkgs) == "table", "depends.is_installed: Argument 'installed_pkgs' is not a table.")
assert(type(version_wanted) == "string" or type(version_wanted) == "nil", "depends.is_installed: Argument 'version_wanted' is not a string or nil.")
local pkg_is_installed, err = false, nil
for _, installed_pkg in pairs(installed_pkgs) do
-- check if package_name is in installed
if package_name == installed_pkg.name then
-- check if package is installed in satisfying version
if not version_wanted or satisfies_constraint(installed_pkg.version, version_wanted) then
pkg_is_installed = true
break
else
err = "Package '" .. package_name .. (version_wanted and " " .. version_wanted or "") .. "' needed, but " .. selected_or_installed(installed_pkg) .. " at version '" .. installed_pkg.version .. "'."
break
end
end
end
return pkg_is_installed, err
end
-- Check whether the package 'pkg' conflicts with 'installed_pkg' and return
-- false or error message.
local function packages_conflicts(pkg, installed_pkg)
assert(type(pkg) == "table", "depends.packages_conflicts: Argument 'pkg' is not a table.")
assert(type(installed_pkg) == "table", "depends.packages_conflicts: Argument 'installed_pkg' is not a table.")
-- check if pkg doesn't provide an already installed_pkg
if pkg.provides then
-- for all of pkg's provides
for _, provided_pkg in pairs(get_provides(pkg)) do
if provided_pkg.name == installed_pkg.name then
return "Package '" .. pkg_full_name(pkg.name, pkg.version, pkg.was_scm_version) .. "' provides '" .. pkg_full_name(provided_pkg.name, provided_pkg.version) .. "' but package '" .. pkg_full_name(installed_pkg.name, installed_pkg.version) .. "' is already " .. selected_or_installed(installed_pkg) .. "."
end
end
end
-- check for conflicts of package to install with installed package
if pkg.conflicts then
for _, conflict in pairs (pkg.conflicts) do
if conflict == installed_pkg.name then
return "Package '" .. pkg_full_name(pkg.name, pkg.version, pkg.was_scm_version) .. "' conflicts with already " .. selected_or_installed(installed_pkg) .. " package '" .. pkg_full_name(installed_pkg.name, installed_pkg.version) .. "'."
end
end
end
-- check for conflicts of installed package with package to install
if installed_pkg.conflicts then
-- direct conflicts with 'pkg'
for _, conflict in pairs (installed_pkg.conflicts) do
if conflict == pkg.name then
return "Already " .. selected_or_installed(installed_pkg) .. " package '" .. pkg_full_name(installed_pkg.name, installed_pkg.version) .. "' conflicts with package '" .. pkg_full_name(pkg.name, pkg.version, pkg.was_scm_version) .. "'."
end
end
-- conflicts with 'provides' of 'pkg' (packages provided by package to install)
if pkg.provides then
for _, conflict in pairs (installed_pkg.conflicts) do
-- for all of pkg's provides
for _, provided_pkg in pairs(get_provides(pkg)) do
if conflict == provided_pkg.name then
return "Already '" .. selected_or_installed(installed_pkg) .. " package '" .. pkg_full_name(installed_pkg.name, installed_pkg.version) .. "' conflicts with package '" .. pkg_full_name(provided_pkg.name, provided_pkg.version) .. "' provided by '" .. pkg_full_name(pkg.name, pkg.version, pkg.was_scm_version) .. "'."
end
end
end
end
end
-- no conflicts found
return false
end
-- Return table of package dependencies 'depends' with OS specific dependencies extracted.
--
-- OS specific dependencies are stored in a subtable with 'arch' as a key.
-- E.g. this table containing OS specific dependencies:
-- depends = {
-- "lua~>5.1",
-- "luadist-git>=0.1",
-- Linux = {
-- "iup>=3.6",
-- "wxlua>=2.8.10.0",
-- },
-- Windows = {
-- "luagd>=2.0.33r2",
-- "luacom>=1.4.1",
-- },
-- }
--
-- ...will be on the 'Linux' architecture (determined by cfg.arch) converted into:
-- depends = {
-- "lua~>5.1",
-- "luadist-git>=0.1",
-- "iup>=3.6",
-- "wxlua>=2.8.10.0",
-- }
function extract_os_specific_depends(depends)
assert(type(depends) == "table", "depends.extract_os_specific_depends: Argument 'depends' is not a table.")
local extracted = {}
for k, depend in pairs(depends) do
-- if 'depend' is a table, then it must be a table of OS specific
-- dependencies, so extract it if it's for this architecture
if type(depend) == "table" then
if k == cfg.arch then
for _, os_specific_depend in pairs(depend) do
table.insert(extracted, os_specific_depend)
end
end
else
table.insert(extracted, depend)
end
end
return extracted
end
-- Return all packages needed in order to install package 'pkg'
-- and with specified 'installed' packages in the system using 'manifest'.
-- 'pkg' can also contain version constraint (e.g. 'copas>=1.2.3', 'saci-1.0' etc.).
--
-- This function also downloads packages to get information about their dependencies.
-- Directory where the package was downloaded is stored in 'download_dir' attribute
-- of that package in the table of packages returned by this function.
--
-- Optional argument 'dependency_manifest' is a table of dependencies examined
-- from previous installations etc. It can be used to speed-up the dependency
-- resolving procedure for example.
--
-- When optional 'force_no_download' parameter is set to true, then information
-- about packages won't be downloaded during dependency resolving, assuming that
-- entries in the provided manifest are already complete.
--
-- When optional 'suppress_printing' parameter is set to true, then messages
-- for the user won't be printed during dependency resolving.
--
-- Optional argument 'deploy_dir' is used just as a temporary place to place
-- the downloaded packages into.
--
-- 'dependency_parents' is table of all packages encountered so far when resolving dependencies
-- and is used to detect and deal with circular dependencies. Leave it 'nil'
-- and it will do its job just fine :-).
--
-- 'tmp_installed' is internal table used in recursion and should be left 'nil' when
-- calling this function from other context. It is used for passing the changes
-- in installed packages between the recursive calls of this function.
--
-- TODO: refactor this spaghetti code!
local function get_packages_to_install(pkg, installed, manifest, dependency_manifest, force_no_download, suppress_printing, deploy_dir, dependency_parents, tmp_installed)
manifest = manifest or mf.get_manifest()
dependency_manifest = dependency_manifest or {}
force_no_download = force_no_download or false
suppress_printing = suppress_printing or false
deploy_dir = deploy_dir or cfg.root_dir
dependency_parents = dependency_parents or {}
-- set helper table 'tmp_installed'
tmp_installed = tmp_installed or utils.deepcopy(installed)
assert(type(pkg) == "string", "depends.get_packages_to_install: Argument 'pkg' is not a string.")
assert(type(installed) == "table", "depends.get_packages_to_install: Argument 'installed' is not a table.")
assert(type(manifest) == "table", "depends.get_packages_to_install: Argument 'manifest' is not a table.")
assert(type(dependency_manifest) == "table", "depends.get_packages_to_install: Argument 'dependency_manifest' is not a table.")
assert(type(force_no_download) == "boolean", "depends.get_packages_to_install: Argument 'force_no_download' is not a boolean.")
assert(type(suppress_printing) == "boolean", "depends.get_packages_to_install: Argument 'suppress_printing' is not a boolean.")
assert(type(deploy_dir) == "string", "depends.get_packages_to_install: Argument 'deploy_dir' is not a string.")
assert(type(dependency_parents) == "table", "depends.get_packages_to_install: Argument 'dependency_parents' is not a table.")
assert(type(tmp_installed) == "table", "depends.get_packages_to_install: Argument 'tmp_installed' is not a table.")
deploy_dir = sys.abs_path(deploy_dir)
--[[ for future debugging:
print('resolving: '.. pkg)
print(' installed: ', utils.table_tostring(installed))
print(' tmp_installed: ', utils.table_tostring(tmp_installed))
--]]
-- check if package is already installed
local pkg_name, pkg_constraint = split_name_constraint(pkg)
local pkg_is_installed, err = is_installed(pkg_name, tmp_installed, pkg_constraint)
if pkg_is_installed then return {} end
if err then return nil, err end
-- table of packages needed to be installed (will be returned)
local to_install = {}
-- find out available versions of 'pkg' and insert them into manifest
if not force_no_download then
local versions, err = package.retrieve_versions(pkg, manifest, suppress_printing)
if not versions then return nil, err end
for _, version in pairs(versions) do
table.insert(manifest, version)
end
end
-- find candidates & sort them
local candidates_to_install = find_packages(pkg, manifest)
if #candidates_to_install == 0 then
return nil, "No suitable candidate for '" .. pkg .. "' found."
end
candidates_to_install = sort_by_versions(candidates_to_install)
for _, pkg in pairs(candidates_to_install) do
--[[ for future debugging:
print(' candidate: '.. pkg.name..'-'..pkg.version)
print(' installed: ', utils.table_tostring(installed))
print(' tmp_installed: ', utils.table_tostring(tmp_installed))
print(' to_install: ', utils.table_tostring(to_install))
print(' -is installed: ', is_installed(pkg.name, tmp_installed, pkg_constraint))
--]]
-- if there's an error from the previous candidate, print the reason for trying another one
if not suppress_printing and err then print(" - trying another candidate due to: " .. err) end
-- clear the state from the previous candidate
pkg_is_installed, err = false, nil
-- check whether this package has already been added to 'tmp_installed' by another of its candidates
pkg_is_installed, err = is_installed(pkg.name, tmp_installed, pkg_constraint)
if pkg_is_installed then break end
-- preserve information about the 'scm' version, because pkg.version
-- will be rewritten by information taken from pkg's dist.info file
local was_scm_version = (pkg.version == "scm")
-- Try to obtain cached dependency information from the dependency manifest
if dependency_manifest[pkg.name .. "-" .. pkg.version] and cfg.dep_cache then
pkg = dependency_manifest[pkg.name .. "-" .. pkg.version]
else
-- download info about the package if not already downloaded and downloading not prohibited
if not (pkg.download_dir or force_no_download) then
local path_or_err
pkg, path_or_err = package.retrieve_pkg_info(pkg, deploy_dir, suppress_printing)
if not pkg then
err = "Error when resolving dependencies: " .. path_or_err
else
-- set path to downloaded package - used to indicate that the
-- package was already downloaded, to delete unused but downloaded
-- packages and also to install choosen packages
pkg.download_dir = path_or_err
end
end
end
if pkg and was_scm_version then pkg.was_scm_version = true end
-- check arch & type
if not err then
if not (pkg.arch == "Universal" or pkg.arch == cfg.arch) or
not (pkg.type == "all" or pkg.type == "source" or pkg.type == cfg.type) then
err = "Package '" .. pkg_full_name(pkg.name, pkg.version) .. "' doesn't have required arch and type."
end
end
-- checks for conflicts with other installed (or previously selected) packages
if not err then
for _, installed_pkg in pairs(tmp_installed) do
err = packages_conflicts(pkg, installed_pkg)
if err then break end
end
end
-- if pkg passed all of the above tests
if not err then
-- check if pkg's dependencies are satisfied
if pkg.depends then
-- insert pkg into the stack of circular dependencies detection
table.insert(dependency_parents, pkg.name)
-- extract all OS specific dependencies of pkg
pkg.depends = extract_os_specific_depends(pkg.depends)
-- for all dependencies of pkg
for _, depend in pairs(pkg.depends) do
local dep_name = split_name_constraint(depend)
-- detect circular dependencies using 'dependency_parents'
local is_circular_dependency = false
for _, parent in pairs(dependency_parents) do
if dep_name == parent then
is_circular_dependency = true
break
end
end
-- if circular dependencies not detected
if not is_circular_dependency then
-- recursively call this function on the candidates of this pkg's dependency
local depends_to_install, dep_err = get_packages_to_install(depend, installed, manifest, dependency_manifest, force_no_download, suppress_printing, deploy_dir, dependency_parents, tmp_installed)
-- if any suitable dependency packages were found, insert them to the 'to_install' table
if depends_to_install then
for _, depend_to_install in pairs(depends_to_install) do
-- add some meta information
if not depend_to_install.selected_by then
depend_to_install.selected_by = pkg.name .. "-" .. pkg.version
end
table.insert(to_install, depend_to_install)
table.insert(tmp_installed, depend_to_install)
table.insert(installed, depend_to_install)
end
else
err = "Error getting dependency of '" .. pkg_full_name(pkg.name, pkg.version) .. "': " .. dep_err
break
end
-- if circular dependencies detected
else
err = "Error getting dependency of '" .. pkg_full_name(pkg.name, pkg.version) .. "': '" .. dep_name .. "' is a circular dependency."
break
end
end
-- remove last package from the stack of circular dependencies detection
table.remove(dependency_parents)
end
-- if no error occured
if not err then
-- add pkg and it's provides to the fake table of installed packages, with
-- property 'selected' set, indicating that the package isn't
-- really installed in the system, just selected to be installed (this is used e.g. in error messages)
pkg.selected = true
table.insert(tmp_installed, pkg)
if pkg.provides then
for _, provided_pkg in pairs(get_provides(pkg)) do
provided_pkg.selected = true
table.insert(tmp_installed, provided_pkg)
end
end
-- add pkg to the table of packages to install
table.insert(to_install, pkg)
-- if some error occured
else
-- delete the downloaded package
if pkg.download_dir and not cfg.debug then sys.delete(pkg.download_dir) end
-- set tables of 'packages to install' and 'installed packages' to their original state
to_install = {}
tmp_installed = utils.deepcopy(installed)
-- add provided packages to installed ones
for _, installed_pkg in pairs(tmp_installed) do
for _, pkg in pairs(get_provides(installed_pkg)) do
table.insert(tmp_installed, pkg)
end
end
end
-- if error occured
else
-- delete the downloaded package
if pkg and pkg.download_dir and not cfg.debug then sys.delete(pkg.download_dir) end
-- if pkg is already installed, skip checking its other candidates
if pkg_is_installed then break end
end
end
-- if package is not installed and no suitable candidates were found, return the last error
if #to_install == 0 and not pkg_is_installed then
return nil, err
else
return to_install
end
end
-- Resolve dependencies and return all packages needed in order to install
-- 'packages' into the system with already 'installed' packages, using 'manifest'.
-- Also return the table of the dependencies determined during the process
-- as the second return value.
--
-- Optional argument 'dependency_manifest' is a table of dependencies examined
-- from previous installations etc. It can be used to speed-up the dependency
-- resolving procedure for example.
--
-- Optional argument 'deploy_dir' is used as a temporary place to place the
-- downloaded packages into.
--
-- When optional 'force_no_download' parameter is set to true, then information
-- about packages won't be downloaded during dependency resolving, assuming that
-- entries in manifest are complete.
--
-- When optional 'suppress_printing' parameter is set to true, then messages
-- for the user won't be printed during dependency resolving.
function get_depends(packages, installed, manifest, dependency_manifest, deploy_dir, force_no_download, suppress_printing)
if not packages then return {} end
manifest = manifest or mf.get_manifest()
dependency_manifest = dependency_manifest or {}
deploy_dir = deploy_dir or cfg.root_dir
force_no_download = force_no_download or false
suppress_printing = suppress_printing or false
if type(packages) == "string" then packages = {packages} end
assert(type(packages) == "table", "depends.get_depends: Argument 'packages' is not a table or string.")
assert(type(installed) == "table", "depends.get_depends: Argument 'installed' is not a table.")
assert(type(manifest) == "table", "depends.get_depends: Argument 'manifest' is not a table.")
assert(type(dependency_manifest) == "table", "depends.get_depends: Argument 'dependency_manifest' is not a table.")
assert(type(deploy_dir) == "string", "depends.get_depends: Argument 'deploy_dir' is not a string.")
assert(type(force_no_download) == "boolean", "depends.get_depends: Argument 'force_no_download' is not a boolean.")
assert(type(suppress_printing) == "boolean", "depends.get_depends: Argument 'suppress_printing' is not a boolean.")
deploy_dir = sys.abs_path(deploy_dir)
local tmp_installed = utils.deepcopy(installed)
-- add provided packages to installed ones
for _, installed_pkg in pairs(tmp_installed) do
for _, pkg in pairs(get_provides(installed_pkg)) do
table.insert(tmp_installed, pkg)
end
end
-- If 'pkg' contains valid (architecture specific) path separator,
-- it is treated like a path to already downloaded package and
-- we assume that user wants to use this specific version of the
-- module to be installed. Hence, we will add information about
-- this version into the manifest and also remove references to
-- any other versions of this module from the manifest. This will
-- enforce the version of the module required by the user.
for k, pkg in pairs(packages) do
if pkg:find(sys.path_separator()) then
local pkg_dir = sys.abs_path(pkg)
local pkg_info, err = mf.load_distinfo(sys.make_path(pkg_dir, "dist.info"))
if not pkg_info then return nil, err end
-- add information about location of the package, also to prevent downloading it again
pkg_info.download_dir = pkg_dir
-- mark package to skip deleting its directory after installation
pkg_info.preserve_pkg_dir = true
-- set default arch/type if not explicitly stated and package is of source type
if package.is_source_type(pkg_dir) then
pkg_info = package.ensure_source_arch_and_type(pkg_info)
elseif not (pkg_info.arch and pkg_info.type) then
return nil, pkg_dir .. ": binary package missing arch or type in 'dist.info'."
end
-- update manifest
manifest = utils.filter(manifest, function(p) return p.name ~= pkg_info.name and true end)
table.insert(manifest, pkg_info)
-- update packages to install
pkg = pkg_info.name .. "-" .. pkg_info.version
packages[k] = pkg
end
end
local to_install = {}
-- get packages needed to satisfy the dependencies
for _, pkg in pairs(packages) do
local needed_to_install, err = get_packages_to_install(pkg, tmp_installed, manifest, dependency_manifest, force_no_download, suppress_printing, deploy_dir)
-- if everything's fine
if needed_to_install then
for _, needed_pkg in pairs(needed_to_install) do
-- TODO: why not to use 'installed' instead of 'tmp_installed'?
-- It's because provides aren't searched for by find()
-- function inside the update_dependency_manifest().
dependency_manifest = update_dependency_manifest(needed_pkg, tmp_installed, needed_to_install, dependency_manifest)
table.insert(to_install, needed_pkg)
table.insert(tmp_installed, needed_pkg)
-- add provides of needed_pkg to installed ones
for _, provided_pkg in pairs(get_provides(needed_pkg)) do
-- copy 'selected' property
provided_pkg.selected = needed_pkg.selected
table.insert(tmp_installed, provided_pkg)
end
end
-- if error occured
else
-- delete already downloaded packages
for _, pkg in pairs(to_install) do
if pkg.download_dir and not cfg.debug then sys.delete(pkg.download_dir) end
end
return nil, "Cannot resolve dependencies for '" .. pkg .. "': ".. err
end
end
return to_install, dependency_manifest
end
-- Return table of packages provided by specified package (from it's 'provides' field)
function get_provides(package)
assert(type(package) == "table", "depends.get_provides: Argument 'package' is not a table.")
if not package.provides then return {} end
local provided = {}
for _, provided_name in pairs(package.provides) do
local pkg = {}
pkg.name, pkg.version = split_name_constraint(provided_name)
pkg.type = package.type
pkg.arch = package.arch
pkg.provided = package.name .. "-" .. package.version
table.insert(provided, pkg)
end
return provided
end
-- Return package name and version constraint from full package version constraint specification
-- E. g.:
-- for 'luaexpat-1.2.3' return: 'luaexpat' , '1.2.3'
-- for 'luajit >= 1.2' return: 'luajit' , '>=1.2'
function split_name_constraint(version_constraint)
assert(type(version_constraint) == "string", "depends.split_name_constraint: Argument 'version_constraint' is not a string.")
local split = version_constraint:find("[%s=~<>-]+%d") or version_constraint:find("[%s=~<>-]+scm")
if split then
return version_constraint:sub(1, split - 1), version_constraint:sub(split):gsub("[%s-]", "")
else
return version_constraint, nil
end
end
-- Return only packages that can be installed on the specified architecture and type
function filter_packages_by_arch_and_type(packages, req_arch, req_type)
assert(type(packages) == "table", "depends.filter_packages_by_arch_and_type: Argument 'packages' is not a table.")
assert(type(req_arch) == "string", "depends.filter_packages_by_arch_and_type: Argument 'req_arch' is not a string.")
assert(type(req_type) == "string", "depends.filter_packages_by_arch_and_type: Argument 'pkg_type' is not a string.")
return utils.filter(packages,
function (pkg)
return (pkg.arch == "Universal" or pkg.arch == req_arch) and
(pkg.type == "all" or pkg.type == "source" or pkg.type == req_type)
end)
end
-- Return only packages that contain one of the specified strings in their 'name-version'.
-- Case is ignored. If no strings are specified, return all the packages.
-- Argument 'search_in_desc' specifies if search also in description of packages.
function filter_packages_by_strings(packages, strings, search_in_desc)
if type(strings) == "string" then strings = {strings} end
assert(type(packages) == "table", "depends.filter_packages_by_strings: Argument 'packages' is not a table.")
assert(type(strings) == "table", "depends.filter_packages_by_strings: Argument 'strings' is not a string or table.")
if #strings ~= 0 then
return utils.filter(packages,
function (pkg)
for _,str in pairs(strings) do
local name = pkg.name .. "-" .. pkg.version
if search_in_desc then
name = name .. " " .. (pkg.desc or "")
end
if string.find(string.lower(name), string.lower(str), 1 ,true) ~= nil then return true end
end
end)
else
return packages
end
end
-- Return full package name and version string (e.g. 'luajit-2.0'). When version
-- is nil or '' then return only name (e.g. 'luajit') and when name is nil or ''
-- then return '<unknown>'. Optional 'was_scm_version' argument is a boolean,
-- stating whether the package was originally selected for installation as a 'scm' version.
function pkg_full_name(name, version, was_scm_version)
name = name or ""
version = version or ""
was_scm_version = was_scm_version or false
if type(version) == "number" then version = tostring(version) end
assert(type(name) == "string", "depends.pkg_full_name: Argument 'name' is not a string.")
assert(type(version) == "string", "depends.pkg_full_name: Argument 'version' is not a string.")
if was_scm_version then version = version .. " [scm version]" end
if name == "" then
return "<unknown>"
else
return name .. ((version ~= "") and "-" .. version or "")
end
end
-- Return table of packages, sorted descendingly by versions (newer ones are moved to the top).
function sort_by_versions(packages)
assert(type(packages) == "table", "depends.sort_by_versions: Argument 'packages' is not a table.")
return utils.sort(packages, function (a, b) return compare_versions(a.version, b.version) end)
end
-- Return table of packages, sorted alphabetically by name and then descendingly by version.
function sort_by_names(packages)
assert(type(packages) == "table", "depends.sort_by_names: Argument 'packages' is not a table.")
return utils.sort(packages, function (a, b)
if a.name == b.name then
return compare_versions(a.version, b.version)
else
return a.name < b.name
end
end)
end
-- Return if version satisfies the specified constraint
function satisfies_constraint(version, constraint)
assert(type(version) == "string", "depends.satisfies_constraint: Argument 'version' is not a string.")
assert(type(constraint) == "string", "depends.satisfies_constraint: Argument 'constraint' is not a string.")
return const.constraint_satisfied(version, constraint)
end
-- For package versions, return whether: 'version_a' > 'version_b'
function compare_versions(version_a, version_b)
assert(type(version_a) == "string", "depends.compare_versions: Argument 'version_a' is not a string.")
assert(type(version_b) == "string", "depends.compare_versions: Argument 'version_b' is not a string.")
return const.compareVersions(version_a, version_b)
end
-- Returns 'dep_manifest' updated with information about the 'pkg'.
-- 'installed' is table with installed packages
-- 'to_install' is table with packages that are selected for installation
-- Packages satisfying the dependencies will be searched for in these two tables.
function update_dependency_manifest(pkg, installed, to_install, dep_manifest)
dep_manifest = dep_manifest or {}
assert(type(pkg) == "table", "depends.update_dependency_manifest: Argument 'pkg' is not a table.")
assert(type(installed) == "table", "depends.update_dependency_manifest: Argument 'installed' is not a table.")
assert(type(to_install) == "table", "depends.update_dependency_manifest: Argument 'to_install' is not a table.")
assert(type(dep_manifest) == "table", "depends.update_dependency_manifest: Argument 'dep_manifest' is not a table.")
local name_ver = pkg.name .. "-" .. (pkg.was_scm_version and "scm" or pkg.version)
-- add to manifest
if not dep_manifest[name_ver] then
dep_manifest[name_ver] = {}
dep_manifest[name_ver].name = pkg.name
dep_manifest[name_ver].version = pkg.version
dep_manifest[name_ver].was_scm_version = pkg.was_scm_version
dep_manifest[name_ver].arch = pkg.arch
dep_manifest[name_ver].type = pkg.type
dep_manifest[name_ver].path = pkg.path
dep_manifest[name_ver].depends = pkg.depends
dep_manifest[name_ver].conflicts = pkg.conflicts
dep_manifest[name_ver].provides = pkg.provides
dep_manifest[name_ver].license = pkg.license
dep_manifest[name_ver].desc = pkg.desc
dep_manifest[name_ver].url = pkg.url
dep_manifest[name_ver].author = pkg.author
dep_manifest[name_ver].maintainer = pkg.maintainer
-- add information which dependency is satisfied by which package
if pkg.depends then
-- TODO: Won't it be better to add OS-specific 'satisfied_by' metadata in a format like OS-specific 'depends' ?
local all_deps = extract_os_specific_depends(pkg.depends)
dep_manifest[name_ver].satisfied_by = {}
for _, depend in pairs(all_deps) do
-- find package satisfying the dependency
local satisfying = find_packages(depend, installed)[1] or find_packages(depend, to_install)[1]
satisfying = satisfying.name .. "-" .. satisfying.version
dep_manifest[name_ver].satisfied_by[depend] = satisfying
-- check whether the satisfying package isn't provided by other one
local provided_by = utils.filter(installed, function(pkg)
return pkg.provides and utils.contains(pkg.provides, satisfying)
end)
if #provided_by == 0 then
provided_by = utils.filter(to_install, function(pkg)
return pkg.provides and utils.contains(pkg.provides, satisfying)
end)
end
if #provided_by ~= 0 then
if not dep_manifest[name_ver].satisfying_provided_by then
dep_manifest[name_ver].satisfying_provided_by = {}
end
dep_manifest[name_ver].satisfying_provided_by[satisfying] = provided_by[1].name .. "-" .. provided_by[1].version
end
end
end
end
return dep_manifest
end

306
lualibs/dist/git.lua vendored Normal file
View File

@@ -0,0 +1,306 @@
-- Encapsulated Git functionality
module ("dist.git", package.seeall)
require "git"
local sys = require "dist.sys"
local cfg = require "dist.config"
-- Clone the repository from url to dest_dir
function clone(repository_url, dest_dir, depth, branch)
assert(type(repository_url) == "string", "git.clone: Argument 'repository_url' is not a string.")
assert(type(dest_dir) == "string", "git.clone: Argument 'dest_dir' is not a string.")
dest_dir = sys.abs_path(dest_dir)
local command = "git clone " .. repository_url
if depth then
assert(type(depth) == "number", "git.clone: Argument 'depth' is not a number.")
command = command .. " --depth " .. depth
end
if branch then
assert(type(branch) == "string", "git.clone: Argument 'branch' is not a string.")
command = command .. " -b " .. branch
end
command = command .. " " .. sys.quote(dest_dir)
if sys.exists(dest_dir) then sys.delete(dest_dir) end
sys.make_dir(dest_dir)
-- change the current working directory to dest_dir
local prev_current_dir = sys.current_dir()
sys.change_dir(dest_dir)
-- execute git clone
if not cfg.debug then command = command .. " -q " end
local ok, err = sys.exec(command)
-- change the current working directory back
sys.change_dir(prev_current_dir)
return ok, err
end
-- Return table of all refs of the remote repository at the 'git_url'. Ref_type can be "tags" or "heads".
local function get_remote_refs(git_url, ref_type)
assert(type(git_url) == "string", "git.get_remote_refs: Argument 'git_url' is not a string.")
assert(type(ref_type) == "string", "git.get_remote_refs: Argument 'ref_type' is not a string.")
assert(ref_type == "tags" or ref_type == "heads", "git.get_remote_refs: Argument 'ref_type' is not \"tags\" or \"heads\".")
local refs = {}
local ok, refs_or_err = pcall(git.protocol.remotes, git_url)
if not ok then return nil, "Error getting refs of the remote repository '" .. git_url .. "': " .. refs_or_err end
for ref, sha in pairs(refs_or_err) do
if ref:match("%S+/" .. ref_type .. "/%S+") and not ref:match("%^{}") then
table.insert(refs, ref:match("%S+/" .. ref_type .. "/(%S+)"))
end
end
return refs
end
-- Return table of all tags of the repository at the 'git_url'
function get_remote_tags(git_url)
return get_remote_refs(git_url, "tags")
end
-- Return table of all branches of the repository at the 'git_url'
function get_remote_branches(git_url)
return get_remote_refs(git_url, "heads")
end
-- Checkout specified ref in specified git_repo_dir
function checkout_ref(ref, git_repo_dir, orphaned)
git_repo_dir = git_repo_dir or sys.current_dir()
orphaned = orphaned or false
assert(type(ref) == "string", "git.checkout_ref: Argument 'ref' is not a string.")
assert(type(git_repo_dir) == "string", "git.checkout_ref: Argument 'git_repo_dir' is not a string.")
assert(type(orphaned) == "boolean", "git.checkout_ref: Argument 'orphaned' is not a boolean.")
git_repo_dir = sys.abs_path(git_repo_dir)
local command = "git checkout "
if orphaned then command = command .. " --orphan " end
command = command .. " " .. ref .. " -f"
if not cfg.debug then command = command .. " -q " end
local ok, err
if git_repo_dir ~= sys.current_dir() then
local prev_current_dir = sys.current_dir()
sys.change_dir(git_repo_dir)
ok, err = sys.exec(command)
sys.change_dir(prev_current_dir)
else
ok, err = sys.exec(command)
end
return ok, err
end
-- Checkout specified sha in specified git_repo_dir
function checkout_sha(sha, git_repo_dir)
git_repo_dir = git_repo_dir or sys.current_dir()
assert(type(sha) == "string", "git.checkout_sha: Argument 'sha' is not a string.")
assert(type(git_repo_dir) == "string", "git.checkout_sha: Argument 'git_repo_dir' is not a string.")
git_repo_dir = sys.abs_path(git_repo_dir)
local dir_changed, prev_current_dir
if git_repo_dir ~= sys.current_dir() then
prev_current_dir = sys.current_dir()
sys.change_dir(git_repo_dir)
dir_changed = true
end
local ok, repo_or_err = pcall(git.repo.open, git_repo_dir)
if not ok then return nil, "Error when opening the git repository '" .. git_repo_dir .. "': " .. repo_or_err end
local err
ok, err = pcall(repo_or_err.checkout, repo_or_err, sha, git_repo_dir)
if not ok then return nil, "Error when checking out the sha '" .. sha .. "' in the git repository '" .. git_repo_dir .. "': " .. err end
repo_or_err:close()
if dir_changed then sys.change_dir(prev_current_dir) end
return true
end
-- Create an empty git repository in given directory.
function init(dir)
dir = dir or sys.current_dir()
assert(type(dir) == "string", "git.init: Argument 'dir' is not a string.")
dir = sys.abs_path(dir)
-- create the 'dir' first, since it causes 'git init' to fail on Windows
-- when the parent directory of 'dir' doesn't exist
local ok, err = sys.make_dir(dir)
if not ok then return nil, err end
local command = "git init " .. sys.quote(dir)
if not cfg.debug then command = command .. " -q " end
return sys.exec(command)
end
-- Add all files in the 'repo_dir' to the git index. The 'repo_dir' must be
-- in the initialized git repository.
function add_all(repo_dir)
repo_dir = repo_dir or sys.current_dir()
assert(type(repo_dir) == "string", "git.add_all: Argument 'repo_dir' is not a string.")
repo_dir = sys.abs_path(repo_dir)
local ok, prev_dir, msg
ok, prev_dir = sys.change_dir(repo_dir);
if not ok then return nil, err end
ok, msg = sys.exec("git add -A -f " .. sys.quote(repo_dir))
sys.change_dir(prev_dir)
return ok, msg
end
-- Commit all indexed files in 'repo_dir' with the given commit 'message'.
-- The 'repo_dir' must be in the initialized git repository.
function commit(message, repo_dir)
repo_dir = repo_dir or sys.current_dir()
message = message or "commit by luadist-git"
assert(type(message) == "string", "git.commit: Argument 'message' is not a string.")
assert(type(repo_dir) == "string", "git.commit: Argument 'repo_dir' is not a string.")
repo_dir = sys.abs_path(repo_dir)
local ok, prev_dir, msg
ok, prev_dir = sys.change_dir(repo_dir);
if not ok then return nil, err end
local command = "git commit -m " .. sys.quote(message)
if not cfg.debug then command = command .. " -q " end
ok, msg = sys.exec(command)
sys.change_dir(prev_dir)
return ok, msg
end
-- Rename branch 'old_name' to 'new_name'. -- The 'repo_dir' must be
-- in the initialized git repository and the branch 'new_name' must
-- not already exist in that repository.
function rename_branch(old_name, new_name, repo_dir)
repo_dir = repo_dir or sys.current_dir()
assert(type(old_name) == "string", "git.rename_branch: Argument 'old_name' is not a string.")
assert(type(new_name) == "string", "git.rename_branch: Argument 'new_name' is not a string.")
assert(type(repo_dir) == "string", "git.rename_branch: Argument 'repo_dir' is not a string.")
repo_dir = sys.abs_path(repo_dir)
local ok, prev_dir, msg
ok, prev_dir = sys.change_dir(repo_dir);
if not ok then return nil, err end
ok, msg = sys.exec("git branch -m " .. old_name .. " " .. new_name)
sys.change_dir(prev_dir)
return ok, msg
end
-- Push the ref 'ref_name' from the 'repo_dir' to the remote git
-- repository 'git_repo_url'. If 'all_tags' is set to true, all tags
-- will be pushed, in addition to the explicitly given ref.
-- If 'delete' is set to 'true' then the explicitly given remote ref
-- will be deleted, not pushed.
function push_ref(repo_dir, ref_name, git_repo_url, all_tags, delete)
repo_dir = repo_dir or sys.current_dir()
all_tags = all_tags or false
delete = delete or false
assert(type(repo_dir) == "string", "git.push_ref: Argument 'repo_dir' is not a string.")
assert(type(git_repo_url) == "string", "git.push_ref: Argument 'git_repo_url' is not a string.")
assert(type(ref_name) == "string", "git.push_ref: Argument 'ref_name' is not a string.")
assert(type(all_tags) == "boolean", "git.push_ref: Argument 'all_tags' is not a boolean.")
assert(type(delete) == "boolean", "git.push_ref: Argument 'delete' is not a boolean.")
repo_dir = sys.abs_path(repo_dir)
local ok, prev_dir, msg
ok, prev_dir = sys.change_dir(repo_dir);
if not ok then return nil, err end
local command = "git push " .. git_repo_url
if all_tags then command = command .. " --tags " end
if delete then command = command .. " --delete " end
command = command .. " " .. ref_name .. " -f "
if not cfg.debug then command = command .. " -q " end
ok, msg = sys.exec(command)
sys.change_dir(prev_dir)
return ok, msg
end
-- Creates the tag 'tag_name' in given 'repo_dir', which must be
-- in the initialized git repository
function create_tag(repo_dir, tag_name)
repo_dir = repo_dir or sys.current_dir()
assert(type(repo_dir) == "string", "git.create_tag: Argument 'repo_dir' is not a string.")
assert(type(tag_name) == "string", "git.create_tag: Argument 'tag_name' is not a string.")
repo_dir = sys.abs_path(repo_dir)
local ok, prev_dir, msg
ok, prev_dir = sys.change_dir(repo_dir);
if not ok then return nil, err end
ok, msg = sys.exec("git tag " .. tag_name .. " -f ")
sys.change_dir(prev_dir)
return ok, msg
end
-- Fetch given 'ref_name' from the remote 'git_repo_url' to the local repository
-- 'repo_dir' and return its sha. 'ref_type' can be "tag" or "head".
local function fetch_ref(repo_dir, git_repo_url, ref_name, ref_type)
repo_dir = repo_dir or sys.current_dir()
assert(type(repo_dir) == "string", "git.fetch_ref: Argument 'repo_dir' is not a string.")
assert(type(git_repo_url) == "string", "git.fetch_ref: Argument 'git_repo_url' is not a string.")
assert(type(ref_name) == "string", "git.fetch_ref: Argument 'ref_name' is not a string.")
assert(type(ref_type) == "string", "git.fetch_ref: Argument 'ref_type' is not a string.")
assert(ref_type == "tag" or ref_type == "head", "git.get_remote_refs: Argument 'ref_type' is not \"tag\" or \"head\".")
repo_dir = sys.abs_path(repo_dir)
local refstring = "refs/" .. ref_type .. "s/" .. ref_name
local suppress_fetch_progress = not cfg.debug
local ok, repo_or_err = pcall(git.repo.open, repo_dir)
if not ok then return nil, "Error when opening the git repository '" .. repo_dir .. "': " .. repo_or_err end
local ok, pack_or_err, sha = pcall(git.protocol.fetch, git_repo_url, repo_or_err, refstring, suppress_fetch_progress)
if not ok then return nil, "Error when fetching ref '" .. refstring .. "' from git repository '" .. git_repo_url .. "': " .. pack_or_err end
repo_or_err:close()
pack_or_err:close()
return sha
end
-- Fetch given 'tag_name' from the remote 'git_repo_url' to the local repository
-- 'repo_dir' and save it as a tag with the same 'tag_name'.
function fetch_tag(repo_dir, git_repo_url, tag_name)
return fetch_ref(repo_dir, git_repo_url, tag_name, "tag")
end
-- Fetch given 'branch_name' from the remote 'git_repo_url' to the local repository
-- 'repo_dir' and save it as a branch with the same 'branch_name'.
function fetch_branch(repo_dir, git_repo_url, branch_name)
return fetch_ref(repo_dir, git_repo_url, branch_name, "head")
end
-- Create the git repository and return the repo object (which can be used in checkout_sha etc.)
-- If the 'dir' exists, it's deleted prior to creating the git repository.
function create_repo(dir)
assert(type(dir) == "string", "git.create_repo: Argument 'dir' is not a string.")
if sys.exists(dir) then sys.delete(dir) end
local ok, repo_or_err = pcall(git.repo.create, dir)
if not ok then return nil, "Error when creating the git repository '" .. dir .. "': " .. repo_or_err end
repo_or_err:close()
return true
end

349
lualibs/dist/init.lua vendored Normal file
View File

@@ -0,0 +1,349 @@
-- main API of LuaDist
module ("dist", package.seeall)
local cfg = require "dist.config"
local depends = require "dist.depends"
local git = require "dist.git"
local sys = require "dist.sys"
local package = require "dist.package"
local mf = require "dist.manifest"
local utils = require "dist.utils"
-- Return the deployment directory.
function get_deploy_dir()
return sys.abs_path(cfg.root_dir)
end
-- Return packages deployed in 'deploy_dir' also with their provides.
function get_deployed(deploy_dir)
deploy_dir = deploy_dir or cfg.root_dir
assert(type(deploy_dir) == "string", "dist.get_deployed: Argument 'deploy_dir' is not a string.")
deploy_dir = sys.abs_path(deploy_dir)
local deployed = depends.get_installed(deploy_dir)
local provided = {}
for _, pkg in pairs(deployed) do
for _, provided_pkg in pairs(depends.get_provides(pkg)) do
provided_pkg.provided_by = pkg.name .. "-" .. pkg.version
table.insert(provided, provided_pkg)
end
end
for _, provided_pkg in pairs(provided) do
table.insert(deployed, provided_pkg)
end
deployed = depends.sort_by_names(deployed)
return deployed
end
-- Download new 'manifest_file' from repository and returns it.
-- Return nil and error message on error.
function update_manifest(deploy_dir)
deploy_dir = deploy_dir or cfg.root_dir
assert(type(deploy_dir) == "string", "dist.update_manifest: Argument 'deploy_dir' is not a string.")
deploy_dir = sys.abs_path(deploy_dir)
-- TODO: use 'deploy_dir' argument in manifest functions
-- retrieve the new manifest (forcing no cache use)
local manifest, err = mf.get_manifest(nil, true)
if manifest then
return manifest
else
return nil, err
end
end
-- Install 'package_names' to 'deploy_dir', using optional CMake 'variables'.
function install(package_names, deploy_dir, variables)
if not package_names then return true end
deploy_dir = deploy_dir or cfg.root_dir
if type(package_names) == "string" then package_names = {package_names} end
assert(type(package_names) == "table", "dist.install: Argument 'package_names' is not a table or string.")
assert(type(deploy_dir) == "string", "dist.install: Argument 'deploy_dir' is not a string.")
deploy_dir = sys.abs_path(deploy_dir)
-- find installed packages
local installed = depends.get_installed(deploy_dir)
-- get manifest
local manifest, err = mf.get_manifest()
if not manifest then return nil, "Error getting manifest: " .. err end
-- get dependency manifest
-- TODO: Is it good that dep_manifest is deploy_dir-specific?
-- Probably it'd be better not to be specific, but then there're
-- problems with 'provides'. E.g. What to do if there's a module
-- installed, that is provided by two different modules in two deploy_dirs?
local dep_manifest_file = sys.abs_path(sys.make_path(deploy_dir, cfg.dep_cache_file))
local dep_manifest, status = {}
if sys.exists(dep_manifest_file) and not utils.cache_timeout_expired(cfg.cache_timeout, dep_manifest_file) then
status, dep_manifest = mf.load_manifest(dep_manifest_file)
if not dep_manifest then return nil, status end
end
-- resolve dependencies
local dependencies, dep_manifest_or_err = depends.get_depends(package_names, installed, manifest, dep_manifest, deploy_dir, false, false)
if not dependencies then return nil, dep_manifest_or_err end
if #dependencies == 0 then return nil, "No packages to install." end
-- save updated dependency manifest
local ok, err = sys.make_dir(sys.parent_dir(dep_manifest_file))
if not ok then return nil, err end
ok, err = mf.save_manifest(dep_manifest_or_err, dep_manifest_file)
if not ok then return nil, err end
-- fetch the packages from repository
local fetched_pkgs = {}
for _, pkg in pairs(dependencies) do
local fetched_pkg, err = package.fetch_pkg(pkg, sys.make_path(deploy_dir, cfg.temp_dir))
if not fetched_pkg then return nil, err end
table.insert(fetched_pkgs, fetched_pkg)
end
-- install fetched packages
for _, pkg in pairs(fetched_pkgs) do
local ok, err = package.install_pkg(pkg.download_dir, deploy_dir, variables, pkg.preserve_pkg_dir)
if not ok then return nil, err end
end
return true
end
-- Manually deploy packages from 'package_dirs' to 'deploy_dir', using optional
-- CMake 'variables'. The 'package_dirs' are preserved (will not be deleted).
function make(deploy_dir, package_dirs, variables)
deploy_dir = deploy_dir or cfg.root_dir
package_dirs = package_dirs or {}
assert(type(deploy_dir) == "string", "dist.make: Argument 'deploy_dir' is not a string.")
assert(type(package_dirs) == "table", "dist.make: Argument 'package_dirs' is not a table.")
deploy_dir = sys.abs_path(deploy_dir)
for _, dir in pairs(package_dirs) do
local ok, err = package.install_pkg(sys.abs_path(dir), deploy_dir, variables, true)
if not ok then return nil, err end
end
return true
end
-- Remove 'package_names' from 'deploy_dir' and return the number of removed
-- packages.
function remove(package_names, deploy_dir)
deploy_dir = deploy_dir or cfg.root_dir
if type(package_names) == "string" then package_names = {package_names} end
assert(type(package_names) == "table", "dist.remove: Argument 'package_names' is not a string or table.")
assert(type(deploy_dir) == "string", "dist.remove: Argument 'deploy_dir' is not a string.")
deploy_dir = sys.abs_path(deploy_dir)
local pkgs_to_remove = {}
local installed = depends.get_installed(deploy_dir)
-- find packages to remove
if #package_names == 0 then
pkgs_to_remove = installed
else
pkgs_to_remove = depends.find_packages(package_names, installed)
end
-- remove them
for _, pkg in pairs(pkgs_to_remove) do
local pkg_distinfo_dir = sys.make_path(cfg.distinfos_dir, pkg.name .. "-" .. pkg.version)
local ok, err = package.remove_pkg(pkg_distinfo_dir, deploy_dir)
if not ok then return nil, err end
end
return #pkgs_to_remove
end
-- Download 'pkg_names' to 'fetch_dir' and return the table of their directories.
function fetch(pkg_names, fetch_dir)
fetch_dir = fetch_dir or sys.current_dir()
assert(type(pkg_names) == "table", "dist.fetch: Argument 'pkg_names' is not a string or table.")
assert(type(fetch_dir) == "string", "dist.fetch: Argument 'fetch_dir' is not a string.")
fetch_dir = sys.abs_path(fetch_dir)
local manifest = mf.get_manifest()
local pkgs_to_fetch = {}
for _, pkg_name in pairs(pkg_names) do
-- retrieve available versions
local versions, err = package.retrieve_versions(pkg_name, manifest)
if not versions then return nil, err end
for _, version in pairs(versions) do
table.insert(manifest, version)
end
local packages = depends.find_packages(pkg_name, manifest)
if #packages == 0 then return nil, "No packages found for '" .. pkg_name .. "'." end
packages = depends.sort_by_versions(packages)
table.insert(pkgs_to_fetch, packages[1])
end
local fetched_dirs = {}
for _, pkg in pairs(pkgs_to_fetch) do
local fetched_pkg, err = package.fetch_pkg(pkg, fetch_dir)
if not fetched_pkg then return nil, err end
table.insert(fetched_dirs, fetched_pkg.download_dir)
end
return fetched_dirs
end
-- Upload binary version of given modules installed in the specified
-- 'deploy_dir' to the repository specified by provided base url.
-- Return the number of uploaded packages.
--
-- Organization of uploaded modules and their repositories is subject
-- to the following conventions:
-- - destination repository is: 'DEST_GIT_BASE_URL/MODULE_NAME'
-- - module will be uploaded to the branch: 'ARCH-TYPE' according
-- to the arch and type of the user's machine
-- - the module will be tagged as: 'VERSION-ARCH-TYPE' (if the tag already
-- exists, it will be overwritten)
--
-- E.g. assume that the module 'lua-5.1.4' is installed on the 32bit Linux
-- system (Linux-i686). When this function is called with the module name
-- 'lua' and base url 'git@github.com:LuaDist', then the binary version
-- of the module 'lua', that is installed on the machine, will be uploaded
-- to the branch 'Linux-i686' of the repository 'git@github.com:LuaDist/lua.git'
-- and tagged as '5.1.4-Linux-i686'.
function upload_modules(deploy_dir, module_names, dest_git_base_url)
deploy_dir = deploy_dir or cfg.root_dir
if type(module_names) == "string" then module_names = {module_names} end
assert(type(deploy_dir) == "string", "dist.upload_module: Argument 'deploy_dir' is not a string.")
assert(type(module_names) == "table", "dist.upload_module: Argument 'module_name' is not a string or table.")
assert(type(dest_git_base_url) == "string", "dist.upload_module: Argument 'dest_git_base_url' is not a string.")
deploy_dir = sys.abs_path(deploy_dir)
local modules_to_upload = {}
local installed = depends.get_installed(deploy_dir)
-- find modules to upload
if #module_names == 0 then
modules_to_upload = installed
else
modules_to_upload = depends.find_packages(module_names, installed)
end
for _, installed_module in pairs(modules_to_upload) do
-- set names
local branch_name = cfg.arch .. "-" .. cfg.type
local tag_name = installed_module.version .. "-" .. branch_name
local full_name = installed_module.name .. "-" .. tag_name
local tmp_dir = sys.make_path(deploy_dir, cfg.temp_dir, full_name .. "-to-upload")
local dest_git_url = dest_git_base_url .. "/" .. installed_module.name .. ".git"
local distinfo_file = sys.make_path(deploy_dir, cfg.distinfos_dir, installed_module.name .. "-" .. installed_module.version, "dist.info")
-- create temporary directory (delete previous if already exists)
if sys.exists(tmp_dir) then sys.delete(tmp_dir) end
local ok, err = sys.make_dir(tmp_dir)
if not ok then return nil, err end
-- copy the module files for all enabled components
for _, component in ipairs(cfg.components) do
if installed_module.files[component] then
for _, file in ipairs(installed_module.files[component]) do
local file_path = sys.make_path(deploy_dir, file)
local dest_dir = sys.parent_dir(sys.make_path(tmp_dir, file))
if sys.is_file(file_path) then
sys.make_dir(dest_dir)
sys.copy(file_path, dest_dir)
end
end
end
end
-- add module's dist.info file
sys.copy(distinfo_file, tmp_dir)
-- create git repo
ok, err = git.init(tmp_dir)
if not ok then return nil, "Error initializing empty git repository in '" .. tmp_dir .. "': " .. err end
-- add all files
ok, err = git.add_all(tmp_dir)
if not ok then return nil, "Error adding all files to the git index in '" .. tmp_dir .. "': " .. err end
-- create commit
ok, err = git.commit("[luadist-git] add " .. full_name .. " [ci skip]", tmp_dir)
if not ok then return nil, "Error commiting changes in '" .. tmp_dir .. "': " .. err end
-- rename branch
ok, err = git.rename_branch("master", branch_name, tmp_dir)
if not ok then return nil, "Error renaming branch 'master' to '" .. branch_name .. "' in '" .. tmp_dir .. "': " .. err end
-- create tag
ok, err = git.create_tag(tmp_dir, tag_name)
if not ok then return nil, "Error creating tag '" .. tag_name .. "' in '" .. tmp_dir .. "': " .. err end
print("Uploading " .. full_name .. " to " .. dest_git_url .. "...")
-- push to the repository
ok, err = git.push_ref(tmp_dir, branch_name, dest_git_url, true)
if not ok then return nil, "Error when pushing branch '" .. branch_name .. "' and tag '" .. tag_name .. "' to '" .. dest_git_url .. "': " .. err end
-- delete temporary directory (if not in debug mode)
if not cfg.debug then sys.delete(tmp_dir) end
end
return #modules_to_upload
end
-- Returns table with information about module's dependencies, using the cache.
function dependency_info(module, deploy_dir)
cache_file = cache_file or sys.abs_path(sys.make_path(cfg.root_dir, cfg.dep_cache_file))
assert(type(module) == "string", "dist.dependency_info: Argument 'module' is not a string.")
assert(type(deploy_dir) == "string", "dist.dependency_info: Argument 'deploy_dir' is not a string.")
-- get manifest
local manifest, err = mf.get_manifest()
if not manifest then return nil, "Error getting manifest: " .. err end
-- get dependency manifest
-- TODO: Is it good that dep_manifest is deploy_dir-specific?
-- Probably it'd be better not to be specific, but then there're
-- problems with 'provides'. E.g. What to do if there's a module
-- installed, that is provided by two different modules in two deploy_dirs?
local dep_manifest_file = sys.abs_path(sys.make_path(deploy_dir, cfg.dep_cache_file))
local dep_manifest, status = {}
if sys.exists(dep_manifest_file) and cfg.cache and not utils.cache_timeout_expired(cfg.cache_timeout, dep_manifest_file) then
status, dep_manifest = mf.load_manifest(dep_manifest_file)
if not dep_manifest then return nil, status end
end
-- force getting the dependency information
local installed = {}
-- resolve dependencies
local dependencies, dep_manifest_or_err = depends.get_depends(module, installed, manifest, dep_manifest, deploy_dir, false, true and not cfg.debug)
if not dependencies then return nil, dep_manifest_or_err end
-- save updated dependency manifest
local ok, err = sys.make_dir(sys.parent_dir(dep_manifest_file))
if not ok then return nil, err end
ok, err = mf.save_manifest(dep_manifest_or_err, dep_manifest_file)
if not ok then return nil, err end
-- collect just relevant dependencies from dependency manifest
local relevant_deps = {}
for _, dep in pairs(dependencies) do
local name_ver = dep.name .. "-" .. (dep.was_scm_version and "scm" or dep.version)
if dep_manifest_or_err[name_ver] then
table.insert(relevant_deps, dep_manifest_or_err[name_ver])
else
return nil, "Error: dependency information for '" .. name_ver .. "' not found in dependency manifest."
end
end
return relevant_deps
end

64
lualibs/dist/logger.lua vendored Normal file
View File

@@ -0,0 +1,64 @@
-- Simple logger for LuaDist.
module ("dist.logger", package.seeall)
local cfg = require "dist.config"
local sys = require "dist.sys"
-- Open 'log_file' and return a log, or nil and error msg on error.
local function get_log(log_file)
log_file = log_file or cfg.log_file
assert(type(log_file) == "string", "log.get_log: Argument 'log_file' is not a string.")
log_file = sys.abs_path(log_file)
sys.make_dir(sys.parent_dir(log_file))
local log, err = io.open(log_file, "a")
if not log then
return nil, "Error: can't open a logfile '" .. log_file .. "': " .. err
else
return log
end
end
-- Set the default log.
local log_file = get_log(cfg.log_file)
-- Log levels used.
local log_levels = {
DEBUG = 0, -- Fine-grained informational events that are most useful to debug an application.
INFO = 1, -- Informational messages that highlight the progress of the application at coarse-grained level.
WARN = 2, -- Potentially harmful situations.
ERROR = 3, -- Error events that might still allow the application to continue running.
FATAL = 4, -- Very severe error events that would presumably lead the application to abort.
}
-- Write 'message' with 'level' to 'log'.
local function write(level, ...)
assert(type(level) == "string", "log.write: Argument 'level' is not a string.")
assert(#arg > 0, "log.write: No message arguments provided.")
assert(type(log_levels[level]) == "number", "log.write: Unknown log level used: '" .. level .. "'.")
level = level:upper()
local message = table.concat(arg, " ")
-- Check if writing for this log level is enabled.
if cfg.write_log_level and log_levels[level] >= log_levels[cfg.write_log_level] then
log_file:write(os.date("%Y-%m-%d %H:%M:%S") .. " [" .. level .. "]\t" .. message .. "\n")
log_file:flush()
end
-- Check if printing for this log level is enabled.
if cfg.print_log_level and log_levels[level] >= log_levels[cfg.print_log_level] then
print(message)
end
end
-- Functions with defined log levels for simple use.
function debug(...) return write("DEBUG", ...) end
function info(...) return write("INFO", ...) end
function warn(...) return write("WARN", ...) end
function error(...) return write("ERROR", ...) end
function fatal(...) return write("FATAL", ...) end
-- Function with explicitly specified log level.
function log(level, ...) return write(level, ...) end

248
lualibs/dist/manifest.lua vendored Normal file
View File

@@ -0,0 +1,248 @@
-- Working with manifest and dist.info files
module ("dist.manifest", package.seeall)
local cfg = require "dist.config"
local git = require "dist.git"
local sys = require "dist.sys"
local utils = require "dist.utils"
-- Return the manifest table from 'manifest_file'. If the manifest is in cache,
-- then the cached version is used. You can set the cache timeout value in
-- 'config.cache_timeout' variable.
-- If optional 'force_no_cache' parameter is true, then the cache is not used.
function get_manifest(manifest_file, force_no_cache)
manifest_file = manifest_file or sys.make_path(cfg.root_dir, cfg.manifest_file)
force_no_cache = force_no_cache or false
assert(type(manifest_file) == "string", "manifest.get_manifest: Argument 'manifest_file' is not a string.")
assert(type(force_no_cache) == "boolean", "manifest.get_manifest: Argument 'force_no_cache' is not a boolean.")
manifest_file = sys.abs_path(manifest_file)
-- download new manifest to the cache if not present or cache not used or cache expired
if not sys.exists(manifest_file) or force_no_cache or not cfg.cache or utils.cache_timeout_expired(cfg.cache_timeout, manifest_file) then
local manifest_dest = sys.parent_dir(manifest_file) or sys.current_dir()
local ok, err = download_manifest(manifest_dest, cfg.repos)
if not ok then return nil, "Error when downloading manifest: " .. err end
end
-- load manifest from cache
local status, ret = load_manifest(manifest_file)
if not status then return nil, "Error when loading manifest: " .. ret end
return ret
end
-- Download manifest from the table of git 'repository_urls' to 'dest_dir' and return true on success
-- and nil and error message on error.
function download_manifest(dest_dir, repository_urls)
dest_dir = dest_dir or sys.make_path(cfg.root_dir, cfg.cache_dir)
repository_urls = repository_urls or cfg.repos
if type(repository_urls) == "string" then repository_urls = {repository_urls} end
assert(type(dest_dir) == "string", "manifest.download_manifest: Argument 'dest_dir' is not a string.")
assert(type(repository_urls) == "table", "manifest.download_manifest: Argument 'repository_urls' is not a table or string.")
dest_dir = sys.abs_path(dest_dir)
-- define used files and directories
local manifest_filename = sys.extract_name(cfg.manifest_file)
local manifest_file = sys.make_path(dest_dir, manifest_filename)
local temp_dir = sys.make_path(cfg.root_dir, cfg.temp_dir)
-- ensure that destination directory exists
local ok, err = sys.make_dir(dest_dir)
if not ok then return nil, err end
-- retrieve manifests from repositories and collect them into one manifest table
local manifest = {}
if #repository_urls == 0 then return nil, "No repository url specified." end
print("Downloading repository information...")
for k, repo in pairs(repository_urls) do
local clone_dir = sys.make_path(temp_dir, "repository_" .. tostring(k))
-- clone the repo and add its '.gitmodules' file to the manifest table
ok, err = git.create_repo(clone_dir)
local sha
if ok then sha, err = git.fetch_branch(clone_dir, repo, "master") end
if sha then ok, err = git.checkout_sha(sha, clone_dir) end
if not (ok and sha) then
if not cfg.debug then sys.delete(clone_dir) end
return nil, "Error when downloading the manifest from repository with url: '" .. repo .. "': " .. err
else
for _, pkg in pairs(load_gitmodules(sys.make_path(clone_dir, ".gitmodules"))) do
table.insert(manifest, pkg)
end
end
if not cfg.debug then sys.delete(clone_dir) end
end
-- save the new manifest table to the file
ok, err = save_manifest(manifest, manifest_file)
if not ok then return nil, err end
return true
end
-- A secure loadfile function
-- If file code chunk has upvalues, the first upvalue is set to the given
-- environement, if that parameter is given, or to the value of the global environment.
local function secure_loadfile(file, env)
assert(type(file) == "string", "secure_loadfile: Argument 'file' is not a string.")
-- use the given (or create a new) restricted environment
local env = env or {}
-- load the file and run in a protected call with the restricted env
-- setfenv is deprecated in lua 5.2 in favor of giving env in arguments
-- the additional loadfile arguments are simply ignored for previous lua versions
local f, err = loadfile(file, 'bt', env)
if f then
if setfenv ~= nil then
setfenv(f, env)
end
return pcall(f)
else
return nil, err
end
end
-- Load and return manifest table from the manifest file.
-- If manifest file not present, return nil.
function load_manifest(manifest_file)
manifest_file = manifest_file or sys.make_path(cfg.root_dir, cfg.manifest_file)
return secure_loadfile(sys.abs_path(manifest_file))
end
-- Load '.gitmodules' file and returns manifest table.
-- If the file is not present, return nil.
function load_gitmodules(gitmodules_file)
gitmodules_file = gitmodules_file or sys.make_path(cfg.root_dir, cfg.manifest_file)
assert(type(gitmodules_file) == "string", "manifest.load_gitmodules: Argument 'gitmodules_file' is not a string.")
gitmodules_file = sys.abs_path(gitmodules_file)
if sys.exists(gitmodules_file) then
-- load the .gitmodules file
local file, err = io.open(gitmodules_file, "r")
if not file then return nil, "Error when opening the .gitmodules file '" .. gitmodules_file .. "':" .. err end
local mf_text = file:read("*a")
file:close()
if not mf_text then return nil, "Error when reading the .gitmodules file '" .. gitmodules_file .. "':" .. err end
manifest = {}
for url in mf_text:gmatch("git://%S+/%S+") do
pkg = {name = url:match("git://%S+/(%S+)%.git") or url:match("git://%S+/(%S+)"), version = "scm", path = url}
table.insert(manifest, pkg)
end
return manifest
else
return nil, "Error when loading the .gitmodules: file '" .. gitmodules_file .. "' doesn't exist."
end
end
-- Save manifest table to the 'file'
function save_manifest(manifest_table, file)
assert(type(manifest_table) == "table", "manifest.save_distinfo: Argument 'manifest_table' is not a table.")
assert(type(file) == "string", "manifest.save_distinfo: Argument 'file' is not a string.")
file = sys.abs_path(file)
-- Print table 'tbl' to io stream 'file'.
local function print_table(file, tbl, in_nested_table)
for k, v in pairs(tbl) do
-- print key
if in_nested_table then file:write("\t\t") end
if type(k) ~= "number" then
file:write("['" .. k .. "']" .. " = ")
end
-- print value
if type(v) == "table" then
file:write("{\n")
print_table(file, v, true)
if in_nested_table then file:write("\t") end
file:write("\t}")
else
if in_nested_table then file:write("\t") end
if type(v) == "string" then
file:write('[[' .. v .. ']]')
else
file:write(tostring(v))
end
end
file:write(",\n")
end
end
local manifest_file = io.open(file, "w")
if not manifest_file then return nil, "Error when saving manifest: cannot open the file '" .. file .. "'." end
manifest_file:write('return {\n')
print_table(manifest_file, manifest_table)
manifest_file:write('},\ntrue')
manifest_file:close()
return true
end
-- Load and return package info table from the distinfo_file file.
-- If file not present, return nil.
function load_distinfo(distinfo_file)
assert(type(distinfo_file) == "string", "manifest.load_distinfo: Argument 'distinfo_file' is not a string.")
distinfo_file = sys.abs_path(distinfo_file)
-- load the distinfo file
local distinfo_env = {}
local status, ret = secure_loadfile(distinfo_file, distinfo_env)
if not status then return nil, "Error when loading package info: " .. ret end
return distinfo_env
end
-- Save distinfo table to the 'file'
function save_distinfo(distinfo_table, file)
assert(type(distinfo_table) == "table", "manifest.save_distinfo: Argument 'distinfo_table' is not a table.")
assert(type(file) == "string", "manifest.save_distinfo: Argument 'file' is not a string.")
file = sys.abs_path(file)
-- Print table 'tbl' to io stream 'file'.
local function print_table(file, tbl, in_nested_table)
for k, v in pairs(tbl) do
-- print key
if type(k) ~= "number" then
file:write(k .. " = ")
end
-- print value
if type(v) == "table" then
file:write("{\n")
print_table(file, v, true)
file:write("}\n")
elseif type(v) == "string" then
if in_nested_table then
file:write('[[' .. v .. ']]')
else
file:write('"' .. v .. '"')
end
else
file:write(v)
end
if in_nested_table then
file:write(",")
end
file:write("\n")
end
end
local distinfo_file = io.open(file, "w")
if not distinfo_file then return nil, "Error when saving dist-info table: cannot open the file '" .. file .. "'." end
print_table(distinfo_file, distinfo_table)
distinfo_file:close()
return true
end

596
lualibs/dist/package.lua vendored Normal file
View File

@@ -0,0 +1,596 @@
-- Package functions
module ("dist.package", package.seeall)
local cfg = require "dist.config"
local git = require "dist.git"
local sys = require "dist.sys"
local mf = require "dist.manifest"
local utils = require "dist.utils"
local depends = require "dist.depends"
-- Return whether the package in given 'pkg_dir' is of a source type.
function is_source_type(pkg_dir)
assert(type(pkg_dir) == "string", "package.is_source_type: Argument 'pkg_dir' is not a string.")
pkg_dir = sys.abs_path(pkg_dir)
return utils.to_boolean(sys.exists(sys.make_path(pkg_dir, "CMakeLists.txt")))
end
-- Ensure proper arch and type for the given source 'dist_info' table and return it.
-- WARNING: this function should be used only for 'dist_info' tables of modules that are of a source type!
function ensure_source_arch_and_type(dist_info)
assert(type(dist_info) == "table", "package.ensure_source_arch_and_type: Argument 'dist_info' is not a table.")
dist_info.arch = dist_info.arch or "Universal"
dist_info.type = dist_info.type or "source"
return dist_info
end
-- Remove package from 'pkg_distinfo_dir' of 'deploy_dir'.
function remove_pkg(pkg_distinfo_dir, deploy_dir)
deploy_dir = deploy_dir or cfg.root_dir
assert(type(pkg_distinfo_dir) == "string", "package.remove_pkg: Argument 'pkg_distinfo_dir' is not a string.")
assert(type(deploy_dir) == "string", "package.remove_pkg: Argument 'deploy_dir' is not a string.")
deploy_dir = sys.abs_path(deploy_dir)
local abs_pkg_distinfo_dir = sys.make_path(deploy_dir, pkg_distinfo_dir)
-- check for 'dist.info'
local info, err = mf.load_distinfo(sys.make_path(abs_pkg_distinfo_dir, "dist.info"))
if not info then return nil, "Error removing package from '" .. pkg_distinfo_dir .. "' - it doesn't contain valid 'dist.info' file." end
if not info.files then return nil, "File '" .. sys.make_path(pkg_distinfo_dir, "dist.info") .."' doesn't contain list of installed files." end
-- remove files installed as components of this package
for _, component in ipairs(cfg.components) do
if info.files[component] then
for i = #info.files[component], 1, -1 do
local f = info.files[component][i]
f = sys.make_path(deploy_dir,f)
if sys.is_file(f) then
sys.delete(f)
elseif sys.is_dir(f) then
local dir_files, err = sys.get_file_list(f)
if not dir_files then return nil, "Error removing package in '" .. abs_pkg_distinfo_dir .. "': " .. err end
if #dir_files == 0 then sys.delete(f) end
end
-- delete also all parent directories if empty
local parents = sys.parents_up_to(f, deploy_dir)
for _, parent in ipairs(parents) do
if sys.is_dir(parent) then
local dir_files, err = sys.get_file_list(parent)
if not dir_files then return nil, "Error removing package in '" .. abs_pkg_distinfo_dir .. "': " .. err end
if #dir_files == 0 then
sys.delete(parent)
end
end
end
end
end
end
-- remove removed components also from 'dist.info'
for _, component in ipairs(cfg.components) do
info.files[component] = nil
end
-- delete the package information from deploy_dir
local ok = sys.delete(abs_pkg_distinfo_dir)
if not ok then return nil, "Error removing package in '" .. abs_pkg_distinfo_dir .. "'." end
-- if the package was not completely removed (e.g. some components remain),
-- save the new version of its 'dist.info'
local comp_num = 0
for _, _ in pairs(info.files) do comp_num = comp_num + 1 end
if comp_num ~= 0 then
sys.make_dir(abs_pkg_distinfo_dir)
local ok, err = mf.save_distinfo(info, sys.make_path(abs_pkg_distinfo_dir, "dist.info"))
if not ok then return nil, "Error resaving the 'dist.info': " .. err end
end
return ok
end
-- Install package from 'pkg_dir' to 'deploy_dir', using optional CMake 'variables'.
-- Optional 'preserve_pkg_dir' argument specified whether to preserve the 'pkg_dir'.
function install_pkg(pkg_dir, deploy_dir, variables, preserve_pkg_dir)
deploy_dir = deploy_dir or cfg.root_dir
variables = variables or {}
preserve_pkg_dir = preserve_pkg_dir or false
assert(type(pkg_dir) == "string", "package.install_pkg: Argument 'pkg_dir' is not a string.")
assert(type(deploy_dir) == "string", "package.install_pkg: Argument 'deploy_dir' is not a string.")
assert(type(variables) == "table", "package.install_pkg: Argument 'variables' is not a table.")
assert(type(preserve_pkg_dir) == "boolean", "package.install_pkg: Argument 'preserve_pkg_dir' is not a boolean.")
pkg_dir = sys.abs_path(pkg_dir)
deploy_dir = sys.abs_path(deploy_dir)
-- check for dist.info
local info, err = mf.load_distinfo(sys.make_path(pkg_dir, "dist.info"))
if not info then return nil, "Error installing: the directory '" .. pkg_dir .. "' doesn't exist or doesn't contain valid 'dist.info' file." end
-- check if the package is source
if is_source_type(pkg_dir) then info = ensure_source_arch_and_type(info) end
-- check package's architecture
if not (info.arch == "Universal" or info.arch == cfg.arch) then
return nil, "Error installing '" .. info.name .. "-" .. info.version .. "': architecture '" .. info.arch .. "' is not suitable for this machine."
end
-- check package's type
if not (info.type == "all" or info.type == "source" or info.type == cfg.type) then
return nil, "Error installing '" .. info.name .. "-" .. info.version .. "': architecture type '" .. info.type .. "' is not suitable for this machine."
end
local ok, err
-- if package is of binary type, just deploy it
if info.type ~= "source" then
ok, err = deploy_binary_pkg(pkg_dir, deploy_dir)
-- else build and then deploy
else
-- check if we have cmake
ok = utils.system_dependency_available("cmake", "cmake --version")
if not ok then return nil, "Error when installing: Command 'cmake' not available on the system." end
-- set cmake variables
local cmake_variables = {}
-- set variables from config file
for k, v in pairs(cfg.variables) do
cmake_variables[k] = v
end
-- set variables specified as argument
for k, v in pairs(variables) do
cmake_variables[k] = v
end
cmake_variables.CMAKE_INCLUDE_PATH = table.concat({cmake_variables.CMAKE_INCLUDE_PATH or "", sys.make_path(deploy_dir, "include")}, ";")
cmake_variables.CMAKE_LIBRARY_PATH = table.concat({cmake_variables.CMAKE_LIBRARY_PATH or "", sys.make_path(deploy_dir, "lib"), sys.make_path(deploy_dir, "bin")}, ";")
cmake_variables.CMAKE_PROGRAM_PATH = table.concat({cmake_variables.CMAKE_PROGRAM_PATH or "", sys.make_path(deploy_dir, "bin")}, ";")
-- build the package and deploy it
ok, err = build_pkg(pkg_dir, deploy_dir, cmake_variables)
if not ok then return nil, err end
end
-- delete directory of fetched package
if not (cfg.debug or preserve_pkg_dir) then sys.delete(pkg_dir) end
return ok, err
end
-- Build and deploy package from 'src_dir' to 'deploy_dir' using 'variables'.
-- Return directory to which the package was built or nil on error.
-- 'variables' is table of optional CMake variables.
function build_pkg(src_dir, deploy_dir, variables)
deploy_dir = deploy_dir or cfg.root_dir
variables = variables or {}
assert(type(src_dir) == "string", "package.build_pkg: Argument 'src_dir' is not a string.")
assert(type(deploy_dir) == "string", "package.build_pkg: Argument 'deploy_dir' is not a string.")
assert(type(variables) == "table", "package.build_pkg: Argument 'variables' is not a table.")
src_dir = sys.abs_path(src_dir)
deploy_dir = sys.abs_path(deploy_dir)
-- check for dist.info
local info, err = mf.load_distinfo(sys.make_path(src_dir, "dist.info"))
if not info then return nil, "Error building package from '" .. src_dir .. "': it doesn't contain valid 'dist.info' file." end
local pkg_name = info.name .. "-" .. info.version
-- set machine information
info.arch = cfg.arch
info.type = cfg.type
-- create CMake build dir
local cmake_build_dir = sys.abs_path(sys.make_path(deploy_dir, cfg.temp_dir, pkg_name .. "-CMake-build"))
sys.make_dir(cmake_build_dir)
-- create cmake cache
variables["CMAKE_INSTALL_PREFIX"] = deploy_dir
local cache_file = io.open(sys.make_path(cmake_build_dir, "cache.cmake"), "w")
if not cache_file then return nil, "Error creating CMake cache file in '" .. cmake_build_dir .. "'" end
-- Fill in cache variables
for k,v in pairs(variables) do
cache_file:write("SET(" .. k .. " " .. sys.quote(v):gsub("\\+", "/") .. " CACHE STRING \"\" FORCE)\n")
end
-- If user cache file is provided then append it
if cfg.cache_file ~= "" then
local user_cache = io.open(sys.abs_path(cfg.cache_file), "r")
if user_cache then
cache_file:write(user_cache:read("*all").."\n")
user_cache:close()
end
end
cache_file:close()
src_dir = sys.abs_path(src_dir)
print("Building " .. sys.extract_name(src_dir) .. "...")
-- set cmake cache command
local cache_command = cfg.cache_command
if cfg.debug then cache_command = cache_command .. " " .. cfg.cache_debug_options end
-- set cmake build command
local build_command = cfg.build_command
if cfg.debug then build_command = build_command .. " " .. cfg.build_debug_options end
-- set the cmake cache
local ok = sys.exec("cd " .. sys.quote(cmake_build_dir) .. " && " .. cache_command .. " " .. sys.quote(src_dir))
if not ok then return nil, "Error preloading the CMake cache script '" .. sys.make_path(cmake_build_dir, "cache.cmake") .. "'" end
-- build with cmake
ok = sys.exec("cd " .. sys.quote(cmake_build_dir) .. " && " .. build_command)
if not ok then return nil, "Error building with CMake in directory '" .. cmake_build_dir .. "'" end
-- if this is only simulation, exit sucessfully, skipping the next actions
if cfg.simulate then
return true, "Simulated build and deployment of package '" .. pkg_name .. "' sucessfull."
end
-- table to collect files installed in the components
info.files = {}
-- install the components
for _, component in ipairs(cfg.components) do
local strip_option = ""
if not cfg.debug and component ~= "Library" then strip_option = cfg.strip_option end
local ok = sys.exec("cd " .. sys.quote(cmake_build_dir) .. " && " .. cfg.cmake .. " " .. strip_option .. " " ..cfg.install_component_command:gsub("#COMPONENT#", component))
if not ok then return nil, "Error when installing the component '" .. component .. "' with CMake in directory '" .. cmake_build_dir .. "'" end
local install_mf = sys.make_path(cmake_build_dir, "install_manifest_" .. component .. ".txt")
local mf, err
local component_files = {}
-- collect files installed in this component
if sys.exists(install_mf) then
mf, err = io.open(install_mf, "r")
if not mf then return nil, "Error when opening the CMake installation manifest '" .. install_mf .. "': " .. err end
for line in mf:lines() do
line = sys.check_separators(line)
local file = line:gsub(utils.escape_magic(deploy_dir .. sys.path_separator()), "")
table.insert(component_files, file)
end
mf:close()
-- add list of component files to the 'dist.info'
if #component_files > 0 then info.files[component] = component_files end
end
end
-- if bookmark == 0 then return nil, "Package did not install any files!" end
-- test with ctest
if cfg.test then
print("Testing " .. sys.extract_name(src_dir) .. " ...")
ok = sys.exec("cd " .. sys.quote(deploy_dir) .. " && " .. cfg.test_command)
if not ok then return nil, "Error when testing the module '" .. pkg_name .. "' with CTest." end
end
-- save modified 'dist.info' file
local pkg_distinfo_dir = sys.make_path(deploy_dir, cfg.distinfos_dir, pkg_name)
sys.make_dir(pkg_distinfo_dir)
ok, err = mf.save_distinfo(info, sys.make_path(pkg_distinfo_dir, "dist.info"))
if not ok then return nil, err end
-- clean up
if not cfg.debug then sys.delete(cmake_build_dir) end
return true, "Package '" .. pkg_name .. "' successfully builded and deployed to '" .. deploy_dir .. "'."
end
-- Deploy binary package from 'pkg_dir' to 'deploy_dir' by copying.
function deploy_binary_pkg(pkg_dir, deploy_dir)
deploy_dir = deploy_dir or cfg.root_dir
assert(type(pkg_dir) == "string", "package.deploy_binary_pkg: Argument 'pkg_dir' is not a string.")
assert(type(deploy_dir) == "string", "package.deploy_binary_pkg: Argument 'deploy_dir' is not a string.")
pkg_dir = sys.abs_path(pkg_dir)
deploy_dir = sys.abs_path(deploy_dir)
-- check for dist.info
local info, err = mf.load_distinfo(sys.make_path(pkg_dir, "dist.info"))
if not info then return nil, "Error deploying package from '" .. pkg_dir .. "': it doesn't contain valid 'dist.info' file." end
local pkg_name = info.name .. "-" .. info.version
-- if this is only simulation, exit sucessfully, skipping the next actions
if cfg.simulate then
return true, "Simulated deployment of package '" .. pkg_name .. "' sucessfull."
end
-- copy all components of the module to the deploy_dir
for _, component in ipairs(cfg.components) do
if info.files[component] then
for _, file in ipairs(info.files[component]) do
local dest_dir = sys.make_path(deploy_dir, sys.parent_dir(file))
local ok, err = sys.make_dir(dest_dir)
if not ok then return nil, "Error when deploying package '" .. pkg_name .. "': cannot create directory '" .. dest_dir .. "': " .. err end
ok, err = sys.copy(sys.make_path(pkg_dir, file), dest_dir)
if not ok then return nil, "Error when deploying package '" .. pkg_name .. "': cannot copy file '" .. file .. "' to the directory '" .. dest_dir .. "': " .. err end
end
end
end
-- copy dist.info to register the module as installed
local pkg_distinfo_dir = sys.make_path(deploy_dir, cfg.distinfos_dir, pkg_name)
sys.make_dir(pkg_distinfo_dir)
ok, err = mf.save_distinfo(info, sys.make_path(pkg_distinfo_dir, "dist.info"))
if not ok then return nil, err end
return true, "Package '" .. pkg_name .. "' successfully deployed to '" .. deploy_dir .. "'."
end
-- Fetch package (table 'pkg') to download_dir. Return the original 'pkg' table
-- with 'pkg.download_dir' containing path to the directory of the
-- downloaded package.
--
-- When optional 'suppress_printing' parameter is set to true, then messages
-- for the user won't be printed during run of this function.
--
-- If the 'pkg' already contains the information about download directory (pkg.download_dir),
-- we assume the package was already downloaded there and won't download it again.
function fetch_pkg(pkg, download_dir, suppress_printing)
download_dir = download_dir or sys.current_dir()
suppress_printing = suppress_printing or false
assert(type(pkg) == "table", "package.fetch_pkg: Argument 'pkg' is not a table.")
assert(type(download_dir) == "string", "package.fetch_pkg: Argument 'download_dir' is not a string.")
assert(type(suppress_printing) == "boolean", "package.fetch_pkg: Argument 'suppress_printing' is not a boolean.")
assert(type(pkg.name) == "string", "package.fetch_pkg: Argument 'pkg.name' is not a string.")
assert(type(pkg.version) == "string", "package.fetch_pkg: Argument 'pkg.version' is not a string.")
-- if the package is already downloaded don't download it again
if pkg.download_dir then return pkg end
assert(type(pkg.path) == "string", "package.fetch_pkg: Argument 'pkg.path' is not a string.")
download_dir = sys.abs_path(download_dir)
local pkg_full_name = pkg.name .. "-" .. pkg.version
local repo_url = pkg.path
local clone_dir = sys.abs_path(sys.make_path(download_dir, pkg_full_name))
pkg.download_dir = clone_dir
-- check if download_dir already exists, assuming the package was already downloaded
if sys.exists(sys.make_path(clone_dir, "dist.info")) then
if cfg.cache and not utils.cache_timeout_expired(cfg.cache_timeout, clone_dir) then
if not suppress_printing then print("'" .. pkg_full_name .. "' already in cache, skipping downloading (use '-cache=false' to force download).") end
return pkg
else
sys.delete(sys.make_path(clone_dir))
end
end
local bin_tag = pkg.version .. "-" .. cfg.arch .. "-" .. cfg.type
local use_binary = false
if cfg.binary then
-- check if binary version of the module for this arch & type available
local avail_tags, err = git.get_remote_tags(repo_url)
if not avail_tags then return nil, err end
if utils.contains(avail_tags, bin_tag) then
use_binary = true
end
end
-- init the git repository
local ok, err = git.create_repo(clone_dir)
if not ok then return nil, err end
-- Fetch the desired ref (from the pkg's remote repo) and checkout into it.
if use_binary then
if not suppress_printing then print("Getting " .. pkg_full_name .. " (binary)...") end
-- We fetch the binary tag.
local sha
if ok then sha, err = git.fetch_tag(clone_dir, repo_url, bin_tag) end
if sha then ok, err = git.checkout_sha(sha, clone_dir) end
elseif cfg.source then
if not suppress_printing then print("Getting " .. pkg_full_name .. " (source)...") end
-- If we want the 'scm' version, we fetch the 'master' branch, otherwise
-- we fetch the tag, matching the desired package version.
if ok and pkg.version ~= "scm" then
local sha
sha, err = git.fetch_tag(clone_dir, repo_url, pkg.version)
if sha then ok, err = git.checkout_sha(sha, clone_dir) end
elseif ok then
local sha
sha, err = git.fetch_branch(clone_dir, repo_url, "master")
if sha then ok, err = git.checkout_sha(sha, clone_dir) end
end
else
ok = false
if cfg.binary then
err = "Binary version of module not available and using source modules disabled."
else
err = "Using both binary and source modules disabled."
end
end
if not ok then
-- clean up
if not cfg.debug then sys.delete(clone_dir) end
return nil, "Error fetching package '" .. pkg_full_name .. "' from '" .. pkg.path .. "' to '" .. download_dir .. "': " .. err
end
-- delete '.git' directory
if not cfg.debug then sys.delete(sys.make_path(clone_dir, ".git")) end
return pkg
end
-- Return table with information about available versions of 'package'.
--
-- When optional 'suppress_printing' parameter is set to true, then messages
-- for the user won't be printed during run of this function.
function retrieve_versions(package, manifest, suppress_printing)
suppress_printing = suppress_printing or false
assert(type(package) == "string", "package.retrieve_versions: Argument 'string' is not a string.")
assert(type(manifest) == "table", "package.retrieve_versions: Argument 'manifest' is not a table.")
assert(type(suppress_printing) == "boolean", "package.retrieve_versions: Argument 'suppress_printing' is not a boolean.")
-- get package table
local pkg_name = depends.split_name_constraint(package)
local tmp_packages = depends.find_packages(pkg_name, manifest)
if #tmp_packages == 0 then
return nil, "No suitable candidate for package '" .. package .. "' found."
else
package = tmp_packages[1]
end
-- if the package's already downloaded, we assume it's desired to install the downloaded version
if package.download_dir then
local pkg_type = "binary"
if is_source_type(package.download_dir) then pkg_type = "source" end
if not suppress_printing then print("Using " .. package.name .. "-" .. package.version .. " (" .. pkg_type .. ") provided by " .. package.download_dir) end
return {package}
end
if not suppress_printing then print("Finding out available versions of " .. package.name .. "...") end
-- get available versions
local tags, err = git.get_remote_tags(package.path)
if not tags then return nil, "Error when retrieving versions of package '" .. package.name .. "': " .. err end
-- filter out tags of binary packages
local versions = utils.filter(tags, function (tag) return tag:match("^[^%-]+%-?[^%-]*$") and true end)
packages = {}
-- create package information
for _, version in pairs(versions) do
pkg = {}
pkg.name = package.name
pkg.version = version
pkg.path = package.path
table.insert(packages, pkg)
end
return packages
end
-- Return table with information from package's dist.info and path to downloaded
-- package. Optional argument 'deploy_dir' is used just as a temporary
-- place to place the downloaded packages into.
--
-- When optional 'suppress_printing' parameter is set to true, then messages
-- for the user won't be printed during the execution of this function.
function retrieve_pkg_info(package, deploy_dir, suppress_printing)
deploy_dir = deploy_dir or cfg.root_dir
assert(type(package) == "table", "package.retrieve_pkg_info: Argument 'package' is not a table.")
assert(type(deploy_dir) == "string", "package.retrieve_pkg_info: Argument 'deploy_dir' is not a string.")
deploy_dir = sys.abs_path(deploy_dir)
local tmp_dir = sys.abs_path(sys.make_path(deploy_dir, cfg.temp_dir))
-- download the package
local fetched_pkg, err = fetch_pkg(package, tmp_dir, suppress_printing)
if not fetched_pkg then return nil, "Error when retrieving the info about '" .. package.name .. "': " .. err end
-- load information from 'dist.info'
local info, err = mf.load_distinfo(sys.make_path(fetched_pkg.download_dir, "dist.info"))
if not info then return nil, err end
-- add other attributes
if package.path then info.path = package.path end
if package.was_scm_version then info.was_scm_version = package.was_scm_version end
-- set default arch/type if not explicitly stated and package is of source type
if is_source_type(fetched_pkg.download_dir) then
info = ensure_source_arch_and_type(info)
elseif not (info.arch and info.type) then
return nil, fetched_pkg.download_dir .. ": binary package missing arch or type in 'dist.info'."
end
return info, fetched_pkg.download_dir
end
-- Return manifest, augmented with info about all available versions
-- of package 'pkg'. Optional argument 'deploy_dir' is used just as a temporary
-- place to place the downloaded packages into.
-- Optional argument 'installed' is manifest of all installed packages. When
-- specified, info from installed packages won't be downloaded from repo,
-- but the dist.info from installed package will be used.
function get_versions_info(pkg, manifest, deploy_dir, installed)
deploy_dir = deploy_dir or cfg.root_dir
assert(type(pkg) == "string", "package.get_versions_info: Argument 'pkg' is not a string.")
assert(type(manifest) == "table", "package.get_versions_info: Argument 'manifest' is not a table.")
assert(type(deploy_dir) == "string", "package.get_versions_info: Argument 'deploy_dir' is not a string.")
deploy_dir = sys.abs_path(deploy_dir)
-- find all available versions of package
local versions, err = retrieve_versions(pkg, manifest)
if not versions then return nil, err end
-- collect info about all retrieved versions
local infos = {}
for _, version in pairs(versions) do
local info, path_or_err
local installed_version = {}
-- find out whether this 'version' is installed so we can use it's dist.info
if type(installed) == "table" then installed_version = depends.find_packages(version.name .. "-" .. version.version, installed) end
-- get info
if #installed_version > 0 then
print("Using dist.info from installed " .. version.name .. "-" .. version.version)
info = installed_version[1]
info.path = version.path
info.from_installed = true -- flag that dist.info of installed package was used
else
info, path_or_err = retrieve_pkg_info(version, deploy_dir)
if not info then return nil, path_or_err end
sys.delete(path_or_err)
end
table.insert(infos, info)
end
-- found and add an implicit 'scm' version
local pkg_name = depends.split_name_constraint(pkg)
local found = depends.find_packages(pkg_name, manifest)
if #found == 0 then return nil, "No suitable candidate for package '" .. pkg .. "' found." end
local scm_info, path_or_err = retrieve_pkg_info({name = pkg_name, version = "scm", path = found[1].path})
if not scm_info then return nil, path_or_err end
sys.delete(path_or_err)
scm_info.version = "scm"
table.insert(infos, scm_info)
local tmp_manifest = utils.deepcopy(manifest)
-- add collected info to the temp. manifest, replacing existing tables
for _, info in pairs(infos) do
local already_in_manifest = false
-- find if this version is already in manifest
for idx, pkg in ipairs(tmp_manifest) do
-- if yes, replace it
if pkg.name == info.name and pkg.version == info.version then
tmp_manifest[idx] = info
already_in_manifest = true
break
end
end
-- if not, just normally add to the manifest
if not already_in_manifest then
table.insert(tmp_manifest, info)
end
end
return tmp_manifest
end

386
lualibs/dist/sys.lua vendored Normal file
View File

@@ -0,0 +1,386 @@
-- System functions
module ("dist.sys", package.seeall)
local cfg = require "dist.config"
local utils = require "dist.utils"
local lfs = require "lfs"
-- Return the path separator according to the platform.
function path_separator()
if cfg.arch == "Windows" then
return "\\"
else
return "/"
end
end
-- Return path with wrong separators replaced with the right ones.
function check_separators(path)
assert(type(path) == "string", "sys.check_separators: Argument 'path' is not a string.")
if cfg.arch == "Windows" then
return path:gsub("/", "\\")
else
return path
end
end
-- Return the path with the unnecessary trailing separator removed.
function remove_trailing(path)
assert(type(path) == "string", "sys.remove_trailing: Argument 'path' is not a string.")
if path:sub(-1) == path_separator() and not is_root(path) then path = path:sub(1,-2) end
return path
end
-- Return the path with the all occurences of '/.' or '\.' (representing
-- the current directory) removed.
function remove_curr_dir_dots(path)
assert(type(path) == "string", "sys.remove_curr_dir_dots: Argument 'path' is not a string.")
while path:match(path_separator() .. "%." .. path_separator()) do -- match("/%./")
path = path:gsub(path_separator() .. "%." .. path_separator(), path_separator()) -- gsub("/%./", "/")
end
return path:gsub(path_separator() .. "%.$", "") -- gsub("/%.$", "")
end
-- Return string argument quoted for a command line usage.
function quote(argument)
assert(type(argument) == "string", "sys.quote: Argument 'argument' is not a string.")
-- TODO: This seems like a not very nice hack. Why is it needed?
-- Wouldn't it be better to fix the problem where it originates?
-- replace '/' path separators for '\' on Windows
if cfg.arch == "Windows" and argument:match("^[%u%U.]?:?[/\\].*") then
argument = argument:gsub("//","\\"):gsub("/","\\")
end
-- Windows doesn't recognize paths starting with two slashes or backslashes
-- so we double every backslash except for the first one
if cfg.arch == "Windows" and argument:match("^[/\\].*") then
local prefix = argument:sub(1,1)
argument = argument:sub(2):gsub("\\", "\\\\")
argument = prefix .. argument
else
argument = argument:gsub("\\", "\\\\")
end
argument = argument:gsub('"', '\\"')
return '"' .. argument .. '"'
end
-- Run the system command (in current directory).
-- Return true on success, nil on fail and log string.
-- When optional 'force_verbose' parameter is true, then the output will be shown
-- even when not in debug or verbose mode.
function exec(command, force_verbose)
force_verbose = force_verbose or false
assert(type(command) == "string", "sys.exec: Argument 'command' is not a string.")
assert(type(force_verbose) == "boolean", "sys.exec: Argument 'force_verbose' is not a boolean.")
if not (cfg.verbose or cfg.debug or force_verbose) then
if cfg.arch == "Windows" then
command = command .. " > NUL 2>&1"
else
command = command .. " > /dev/null 2>&1"
end
end
if cfg.debug then print("Executing the command: " .. command) end
local ok, str, status = os.execute(command)
-- os.execute returned values on failure are:
-- nil or true, "exit", n or true, "signal", n for lua >= 5.2
-- status ~= 0 for lua 5.x < 5.2
if ok == nil or (str == "exit" and status ~= 0) or str == "signal" or (ok ~= 0 and ok ~= true) then
return nil, "Error when running the command: " .. command
else
return true, "Sucessfully executed the command: " .. command
end
end
-- Execute the 'command' and returns its output as a string.
function capture_output(command)
assert(type(command) == "string", "sys.exec: Argument 'command' is not a string.")
local executed, err = io.popen(command, "r")
if not executed then return nil, "Error running the command '" .. command .. "':" .. err end
local captured, err = executed:read("*a")
if not captured then return nil, "Error reading the output of command '" .. command .. "':" .. err end
executed:close()
return captured
end
-- Return whether the path is a root.
function is_root(path)
assert(type(path) == "string", "sys.is_root: Argument 'path' is not a string.")
return utils.to_boolean(path:find("^[a-zA-Z]:[/\\]$") or path:find("^[/\\]$"))
end
-- Return whether the path is absolute.
function is_abs(path)
assert(type(path) == "string", "sys.is_abs: Argument 'path' is not a string.")
return utils.to_boolean(path:find("^[a-zA-Z]:[/\\].*$") or path:find("^[/\\].*$"))
end
-- Return whether the specified file or directory exists.
function exists(path)
assert(type(path) == "string", "sys.exists: Argument 'path' is not a string.")
local attr, err = lfs.attributes(path)
return utils.to_boolean(attr), err
end
-- Return whether the 'file' exists and is a file.
function is_file(file)
assert(type(file) == "string", "sys.is_file: Argument 'file' is not a string.")
return lfs.attributes(file, "mode") == "file"
end
-- Return whether the 'dir' exists and is a directory.
function is_dir(dir)
assert(type(dir) == "string", "sys.is_dir: Argument 'dir' is not a string.")
return lfs.attributes(dir, "mode") == "directory"
end
-- Return the current working directory
function current_dir()
local dir, err = lfs.currentdir()
if not dir then return nil, err end
return dir
end
-- Return an iterator over the directory 'dir'.
-- If 'dir' doesn't exist or is not a directory, return nil and error message.
function get_directory(dir)
dir = dir or current_dir()
assert(type(dir) == "string", "sys.get_directory: Argument 'dir' is not a string.")
if is_dir(dir) then
return lfs.dir(dir)
else
return nil, "Error: '".. dir .. "' is not a directory."
end
end
-- Extract file or directory name from its path.
function extract_name(path)
assert(type(path) == "string", "sys.extract_name: Argument 'path' is not a string.")
if is_root(path) then return path end
path = remove_trailing(path)
path = path:gsub("^.*" .. path_separator(), "")
return path
end
-- Return parent directory of the 'path' or nil if there's no parent directory.
-- If 'path' is a path to file, return the directory the file is in.
function parent_dir(path)
assert(type(path) == "string", "sys.parent_dir: Argument 'path' is not a string.")
path = remove_curr_dir_dots(path)
path = remove_trailing(path)
local dir = path:gsub(utils.escape_magic(extract_name(path)) .. "$", "")
if dir == "" then
return nil
else
return make_path(dir)
end
end
-- Returns the table of all parent directories of 'path' up to the directory
-- specified by 'boundary_path' (exclusive).
function parents_up_to(path, boundary_path)
assert(type(path) == "string", "sys.parents_up_to: Argument 'path' is not a string.")
assert(type(boundary_path) == "string", "sys.parents_up_to: Argument 'boundary_path' is not a string.")
boundary_path = remove_trailing(boundary_path)
-- helper function to recursively collect the parent directories
local function collect_parents(_path, _parents)
local _parent = parent_dir(_path)
if _parent and _parent ~= boundary_path then
table.insert(_parents, _parent)
return collect_parents(_parent, _parents)
else
return _parents
end
end
return collect_parents(path, {})
end
-- Compose path composed from specified parts or current
-- working directory when no part specified.
function make_path(...)
-- arg is deprecated in lua 5.2 in favor of table.pack we mimic here
local arg = {n=select('#',...),...}
local parts = arg
assert(type(parts) == "table", "sys.make_path: Argument 'parts' is not a table.")
local path, err
if parts.n == 0 then
path, err = current_dir()
else
path, err = table.concat(parts, path_separator())
end
if not path then return nil, err end
-- squeeze repeated occurences of a file separator
path = path:gsub(path_separator() .. "+", path_separator())
-- remove unnecessary trailing path separator
path = remove_trailing(path)
return path
end
-- Return absolute path from 'path'
function abs_path(path)
assert(type(path) == "string", "sys.get_abs_path: Argument 'path' is not a string.")
if is_abs(path) then return path end
local cur_dir, err = current_dir()
if not cur_dir then return nil, err end
return make_path(cur_dir, path)
end
-- Returns path to the temporary directory of OS.
function tmp_dir()
return os.getenv("TMPDIR") or os.getenv("TEMP") or os.getenv("TMP") or "/tmp"
end
-- Returns temporary file (or directory) path (with optional prefix).
function tmp_name(prefix)
prefix = prefix or ""
assert(type(prefix) == "string", "sys.tmp_name: Argument 'prefix' is not a string.")
return make_path(tmp_dir(), prefix .. "luadist_" .. utils.rand(10000000000))
end
-- Return table of all paths in 'dir'
function get_file_list(dir)
dir = dir or current_dir()
assert(type(dir) == "string", "sys.get_directory: Argument 'dir' is not a string.")
if not exists(dir) then return nil, "Error getting file list of '" .. dir .. "': directory doesn't exist." end
local function collect(path, all_paths)
for item in get_directory(path) do
local item_path = make_path(path, item)
local _, last = item_path:find(dir .. path_separator(), 1, true)
local path_to_insert = item_path:sub(last + 1)
if is_file(item_path) then
table.insert(all_paths, path_to_insert)
elseif is_dir(item_path) and item ~= "." and item ~= ".." then
table.insert(all_paths, path_to_insert)
collect(item_path, all_paths)
end
end
end
local all_paths = {}
collect(dir, all_paths)
return all_paths
end
-- Return time of the last modification of 'file'.
function last_modification_time(file)
assert(type(file) == "string", "sys.last_modification_time: Argument 'file' is not a string.")
return lfs.attributes(file, "modification")
end
-- Return the current time (in seconds since epoch).
function current_time()
return os.time()
end
-- Change the current working directory and return 'true' and previous working
-- directory on success and 'nil' and error message on error.
function change_dir(dir_name)
assert(type(dir_name) == "string", "sys.change_dir: Argument 'dir_name' is not a string.")
local prev_dir = current_dir()
local ok, err = lfs.chdir(dir_name)
if ok then
return ok, prev_dir
else
return nil, err
end
end
-- Make a new directory, making also all of its parent directories that doesn't exist.
function make_dir(dir_name)
assert(type(dir_name) == "string", "sys.make_dir: Argument 'dir_name' is not a string.")
if exists(dir_name) then
return true
else
local par_dir = parent_dir(dir_name)
if par_dir then
local ok, err = make_dir(par_dir)
if not ok then return nil, err end
end
return lfs.mkdir(dir_name)
end
end
-- Move file (or directory) to the destination directory
function move_to(file_or_dir, dest_dir)
assert(type(file_or_dir) == "string", "sys.move_to: Argument 'file_or_dir' is not a string.")
assert(type(dest_dir) == "string", "sys.move_to: Argument 'dest_dir' is not a string.")
assert(is_dir(dest_dir), "sys.move_to: Destination '" .. dest_dir .."' is not a directory.")
-- Extract file/dir name from its path
local file_or_dir_name = extract_name(file_or_dir)
return os.rename(file_or_dir, make_path(dest_dir, file_or_dir_name))
end
-- rename file (or directory) to the new name.
function rename(file, new_name)
assert(type(file) == "string", "sys.rename: Argument 'file' is not a string.")
assert(type(new_name) == "string", "sys.rename: Argument 'new_name' is not a string.")
assert(not exists(new_name), "sys.rename: desired filename already exists.")
return os.rename(file, new_name)
end
-- Copy 'source' to the destination directory 'dest_dir'.
-- If 'source' is a directory, then recursive copying is used.
-- For non-recursive copying of directories use the make_dir() function.
function copy(source, dest_dir)
assert(type(source) == "string", "sys.copy: Argument 'file_or_dir' is not a string.")
assert(type(dest_dir) == "string", "sys.copy: Argument 'dest_dir' is not a string.")
assert(is_dir(dest_dir), "sys.copy: destination '" .. dest_dir .."' is not a directory.")
if cfg.arch == "Windows" then
if is_dir(source) then
make_dir(make_path(dest_dir, extract_name(source)))
return exec("xcopy /E /I /Y /Q " .. quote(source) .. " " .. quote(dest_dir .. "\\" .. extract_name(source)))
else
return exec("copy /Y " .. quote(source) .. " " .. quote(dest_dir))
end
else
if is_dir(source) then
return exec("cp -fRH " .. quote(source) .. " " .. quote(dest_dir))
else
return exec("cp -fH " .. quote(source) .. " " .. quote(dest_dir))
end
end
end
-- Delete the specified file or directory
function delete(path)
assert(type(path) == "string", "sys.delete: Argument 'path' is not a string.")
assert(is_abs(path), "sys.delete: Argument 'path' is not an absolute path.")
if cfg.arch == "Windows" then
if not exists(path) then
return true
elseif is_file(path) then
return os.remove(path)
else
return exec("rd /S /Q " .. quote(path))
end
else
return exec("rm -rf " .. quote(path))
end
end

151
lualibs/dist/utils.lua vendored Normal file
View File

@@ -0,0 +1,151 @@
-- System functions
module ("dist.utils", package.seeall)
local sys = require "dist.sys"
-- Returns a deep copy of 'table' with reference to the same metadata table.
-- Source: http://lua-users.org/wiki/CopyTable
function deepcopy(object)
local lookup_table = {}
local function _copy(object)
if type(object) ~= "table" then
return object
elseif lookup_table[object] then
return lookup_table[object]
end
local new_table = {}
lookup_table[object] = new_table
for index, value in pairs(object) do
new_table[_copy(index)] = _copy(value)
end
return setmetatable(new_table, getmetatable(object))
end
return _copy(object)
end
-- Return deep copy of table 'array', containing only items for which 'predicate_fn' returns true.
function filter(array, predicate_fn)
assert(type(array) == "table", "utils.filter: Argument 'array' is not a table.")
assert(type(predicate_fn) == "function", "utils.filter: Argument 'predicate_fn' is not a function.")
local filtered = {}
for _,v in pairs(array) do
if predicate_fn(v) == true then table.insert(filtered, deepcopy(v)) end
end
return filtered
end
-- Return deep copy of table 'array', sorted according to the 'compare_fn' function.
function sort(array, compare_fn)
assert(type(array) == "table", "utils.sort: Argument 'array' is not a table.")
assert(type(compare_fn) == "function", "utils.sort: Argument 'compare_fn' is not a function.")
local sorted = deepcopy(array)
table.sort(sorted, compare_fn)
return sorted
end
-- Return whether the 'value' is in the table 'tbl'.
function contains(tbl, value)
assert(type(tbl) == "table", "utils.contains: Argument 'tbl' is not a table.")
for _,v in pairs(tbl) do
if v == value then return true end
end
return false
end
-- Return single line string consisting of values in 'tbl' separated by comma.
-- Used for printing the dependencies/provides/conflicts.
function table_tostring(tbl, label)
assert(type(tbl) == "table", "utils.table_tostring: Argument 'tbl' is not a table.")
local str = ""
for k,v in pairs(tbl) do
if type(v) == "table" then
str = str .. table_tostring(v, k)
else
if label ~= nil then
str = str .. tostring(v) .. " [" .. tostring(label) .. "]" .. ", "
else
str = str .. tostring(v) .. ", "
end
end
end
return str
end
-- Return table made up from values of the string, separated by separator.
function make_table(str, separator)
assert(type(str) == "string", "utils.make_table: Argument 'str' is not a string.")
assert(type(separator) == "string", "utils.make_table: Argument 'separator' is not a string.")
local tbl = {}
for val in str:gmatch("(.-)" .. separator) do
table.insert(tbl, val)
end
local last_val = str:gsub(".-" .. separator, "")
if last_val and last_val ~= "" then
table.insert(tbl, last_val)
end
return tbl
end
-- Return whether the 'cache_timeout' for 'file' has expired.
function cache_timeout_expired(cache_timeout, file)
assert(type(cache_timeout) == "number", "utils.cache_timeout_expired: Argument 'cache_timeout' is not a number.")
assert(type(file) == "string", "utils.cache_timeout_expired: Argument 'file' is not a string.")
return sys.last_modification_time(file) + cache_timeout < sys.current_time()
end
-- Return the string 'str', with all magic (pattern) characters escaped.
function escape_magic(str)
assert(type(str) == "string", "utils.escape: Argument 'str' is not a string.")
local escaped = str:gsub('[%-%.%+%[%]%(%)%^%%%?%*%^%$]','%%%1')
return escaped
end
-- Return the boolean representation of an 'arg'.
function to_boolean(arg)
return not not arg
end
math.randomseed(os.time())
-- Return pseudo-random number in range [0, 1], [1, n] or [n, m].
function rand(...)
return math.random(...)
end
-- Perform check of system dependency, which isn't provided in the LuaDist
-- installation itself and if it is missing, print instructions how
-- to install it. The 'command' is used for testing, 'name' when printing
-- information to the user.
function system_dependency_available(name, command)
assert(type(name) == "string", "utils.system_dependency_available: Argument 'name' is not a string.")
assert(type(command) == "string", "utils.system_dependency_available: Argument 'command' is not a string.")
if not sys.exec(command) then
print("Error: command '" .. name .. "' not found on system. See installation instructions at\nhttps://github.com/LuaDist/Repository/wiki/Installation-of-System-Dependencies")
return false
end
return true
end
-- Obtain LuaDist location by checking available package locations
function get_luadist_location()
local paths = {}
local path = package.path:gsub("([^;]+)", function(c) table.insert(paths, c) end)
for _, path in pairs(paths) do
if (sys.is_abs(path) and path:find("[/\\]lib[/\\]lua[/\\]%?.lua$")) then
-- Remove path to lib/lua
path = path:gsub("[/\\]lib[/\\]lua[/\\]%?.lua$", "")
-- Clean the path up a bit
path = path:gsub("[/\\]bin[/\\]%.[/\\]%.%.", "")
path = path:gsub("[/\\]bin[/\\]%.%.", "")
return path
end
end
return nil
end

5
lualibs/git.lua Normal file
View File

@@ -0,0 +1,5 @@
require 'git.util'
require 'git.objects'
require 'git.pack'
require 'git.repo'
require 'git.protocol'

121
lualibs/git/objects.lua Normal file
View File

@@ -0,0 +1,121 @@
local util = require 'git.util'
local assert, next, io, print, os, type, string, pairs, tostring =
assert, next, io, print, os, type, string, pairs, tostring
local join_path = git.util.join_path
local require = require
local isPosix = package.config:sub(1,1) == '/' -- wild guess
module(...)
Commit = {}
Commit.__index = Commit
function Commit:tree()
return self.repo:tree(self.tree_sha)
end
function Commit:checkout(path)
assert(path, 'path argument missing')
self:tree():checkoutTo(path)
end
Tree = {}
Tree.__index = function (t,k)
if Tree[k] then return Tree[k] end
return t:entry(k)
end
function Tree:entries()
return function(t, n)
local n, entry = next(t, n)
if entry then
local object
if entry.type == 'tree' then
object = self.repo:tree(entry.id)
elseif entry.type == 'blob' then
object = self.repo:blob(entry.id)
object.mode = entry.mode
elseif entry.type == 'commit' then
-- this is possibly a commit in a submodule,
-- do not retrieve it from current repo
object = entry
else
error('Unknown entry type: ' .. entry.type)
end
return n, entry.type, object
end
end, self._entries
end
function Tree:entry(n)
local e = self._entries[n]
if not e then return end
if e.type == 'tree' then
return self.repo:tree(e.id)
elseif e.type == 'commit' then
return self.repo:commit(e.id)
elseif e.type == 'blob' then
return self.repo:blob(e.id)
else
error('Unknown entry type: ' .. e.type)
end
end
function Tree:walk(func, path)
path = path or '.'
assert(type(func) == "function", "argument is not a function")
local function walk(tree, path)
for name, type, entry in tree:entries() do
local entry_path = join_path(path, name)
func(entry, entry_path, type)
if type == "tree" then
walk(entry, entry_path)
end
end
end
walk(self, path)
end
function Tree:checkoutTo(path)
util.make_dir(path)
self:walk(function (entry, entry_path, type)
if type == 'tree' then
util.make_dir(entry_path)
elseif type == 'blob' then
local out = assert(io.open(entry_path, 'wb'))
out:write(entry:content())
out:close()
if isPosix then
local mode = entry.mode:sub(-3,-1) -- fixme: is this ok?
local cmd = 'chmod '..mode..' "'..entry_path..'"'
os.execute(cmd)
end
elseif type == 'commit' then
-- this is a submodule referencing a commit,
-- make a directory for it
util.make_dir(entry_path)
else
error('Unknown entry type: ', type)
end
end, path)
end
Blob = {}
Blob.__index = Blob
function Blob:content()
if self.stored then
local f = self.repo:raw_object(self.id)
local ret = f:read('*a') or ""
f:close()
return ret
else
return self.data
end
end

316
lualibs/git/pack.lua Normal file
View File

@@ -0,0 +1,316 @@
local io = io
local core = require 'git.core'
local assert, pcall, print, select, setmetatable, string, type, unpack =
assert, pcall, print, select, setmetatable, string, type, unpack
local ord = string.byte
local fmt = string.format
local concat, insert = table.concat, table.insert
local band = core.band
local rshift, lshift = core.rshift, core.lshift
local to_hex = git.util.to_hex
local from_hex = git.util.from_hex
local object_sha = git.util.object_sha
local binary_sha = git.util.binary_sha
local readable_sha = git.util.readable_sha
local tmpfile = git.util.tmpfile
local reader = git.util.reader
module(...)
-- read git/Documentation/technical/pack-format.txt for some inspiration
-- 1 = commit, 2 = tree ...
local types = {'commit', 'tree', 'blob', 'tag', '???', 'ofs_delta', 'ref_delta'}
-- read a 4 byte unsigned integer stored in network order
local function read_int(f)
local s = f:read(4)
local a,b,c,d = s:byte(1,4)
return a*256^3 + b*256^2 + c*256 + d
end
-- read in the type and file length
local function read_object_header(f)
local b = ord(f:read(1))
local type = band(rshift(b, 4), 0x7)
local len = band(b, 0xF)
local ofs = 0
while band(b, 0x80) ~= 0 do
b = ord(f:read(1))
len = len + lshift(band(b, 0x7F), ofs * 7 + 4)
ofs = ofs + 1
end
return len, type
end
-- reads in the delta header and returns the offset where original data is stored
local function read_delta_header(f)
local b = ord(f:read(1))
local offset = band(b, 0x7F)
while band(b, 0x80) ~= 0 do
offset = offset + 1
b = ord(f:read(1))
offset = lshift(offset, 7) + band(b, 0x7F)
end
return offset
end
-- read just enough of file `f` to uncompress `size` bytes
local function uncompress_by_len(f, size)
local z = core.inflate()
local chunks = {}
local CHUNK_SIZE = 1024
local curr_pos = f:seek()
local inflated, eof, total
-- read until end of zlib-compresed stream
while not eof do
local data = f:read(CHUNK_SIZE)
inflated, eof, total = z(data)
insert(chunks, inflated)
end
-- repair the current position in stream
f:seek('set', curr_pos + total)
return concat(chunks)
end
-- uncompress the object from the current location in `f`
local function unpack_object(f, len, type)
local data = uncompress_by_len(f, len)
return data, len, type
end
-- returns a size value encoded in delta data
local function delta_size(f)
local size = 0
local i = 0
repeat
local b = ord(f:read(1))
size = size + lshift(band(b, 0x7F), i)
i = i + 7
until band(b, 0x80) == 0
return size
end
-- returns a patched object from string `base` according to `delta` data
local function patch_object(base, delta, base_type)
-- insert delta codes into temporary file
local df = reader(delta)
-- retrieve original and result size (for checks)
local orig_size = delta_size(df)
assert(#base == orig_size, fmt('#base(%d) ~= orig_size(%d)', #base, orig_size))
local result_size = delta_size(df)
local size = result_size
local result = {}
-- process the delta codes
local cmd = df:read(1)
while cmd do
cmd = ord(cmd)
if cmd == 0 then
error('unexpected delta code 0')
elseif band(cmd, 0x80) ~= 0 then -- copy a selected part of base data
local cp_off, cp_size = 0, 0
-- retrieve offset
if band(cmd, 0x01) ~= 0 then cp_off = ord(df:read(1)) end
if band(cmd, 0x02) ~= 0 then cp_off = cp_off + ord(df:read(1))*256 end
if band(cmd, 0x04) ~= 0 then cp_off = cp_off + ord(df:read(1))*256^2 end
if band(cmd, 0x08) ~= 0 then cp_off = cp_off + ord(df:read(1))*256^3 end
-- retrieve size
if band(cmd, 0x10) ~= 0 then cp_size = ord(df:read(1)) end
if band(cmd, 0x20) ~= 0 then cp_size = cp_size + ord(df:read(1))*256 end
if band(cmd, 0x40) ~= 0 then cp_size = cp_size + ord(df:read(1))*256^2 end
if cp_size == 0 then cp_size = 0x10000 end
if cp_off + cp_size > #base or cp_size > size then break end
-- get the data and append it to result
local data = base:sub(cp_off + 1, cp_off + cp_size)
insert(result, data)
size = size - cp_size
else -- insert new data
if cmd > size then break end
local data = df:read(cmd)
insert(result, data)
size = size - cmd
end
cmd = df:read(1)
end
df:close()
result = concat(result)
assert(#result == result_size, fmt('#result(%d) ~= result_size(%d)', #result, result_size))
return result, result_size, base_type
end
Pack = {}
Pack.__index = Pack
-- read an object from the current location in pack, or from a specific `offset`
-- if specified
function Pack:read_object(offset, ignore_data)
local f = self.pack_file
if offset then
f:seek('set', offset)
end
local curr_pos = f:seek()
local len, type = read_object_header(f)
if type < 5 then -- commit, tree, blob, tag
return unpack_object(f, len, type)
elseif type == 6 then -- ofs_delta
local offset = read_delta_header(f)
local delta_data = uncompress_by_len(f, len)
if not ignore_data then
-- the offset is negative from the current location
local base, base_len, base_type = self:read_object(curr_pos - offset)
return patch_object(base, delta_data, base_type)
end
elseif type == 7 then -- ref_delta
local sha = f:read(20)
local delta_data = uncompress_by_len(f, len)
if not ignore_data then
-- lookup the object in the pack by sha
-- FIXME: maybe lookup in repo/other packs
local base_offset = self.index[binary_sha(sha)]
local base, base_len, base_type = self:read_object(base_offset)
return patch_object(base, delta_data, base_type)
end
else
error('unknown object type: '..type)
end
end
-- returns true if this pack contains the given object
function Pack:has_object(sha)
return self.index[binary_sha(sha)] ~= nil
end
-- if the object name `sha` exists in the pack, returns a temporary file with the
-- object content, length and type, otherwise returns nil
function Pack:get_object(sha)
local offset = self.index[binary_sha(sha)]
if not offset then
print('!!! Failed to find object', readable_sha(sha))
end
local data, len, type = self:read_object(offset)
print(readable_sha(sha), len, type, data)
local f = tmpfile()
f:write(data)
f:seek('set', 0)
return f, len, types[type]
end
function Pack:unpack(repo)
for i=1, self.nobjects do
local offset = self.offsets[i]
local data, len, type = self:read_object(offset)
repo:store_object(data, len, types[type])
end
end
-- parses the index
function Pack:parse_index(index_file)
local f = index_file
local head = f:read(4)
assert(head == '\255tOc', "Incorrect header: " .. head)
local version = read_int(f)
assert(version == 2, "Incorrect version: " .. version)
-- first the fanout table (how many objects are in the index, whose
-- first byte is below or equal to i)
local fanout = {}
for i=0, 255 do
local nobjs = read_int(f)
fanout[i] = nobjs
end
-- the last element in fanout is the number of all objects in index
local count = fanout[255]
-- then come the sorted object names (=sha hash)
local tmp = {}
for i=1,count do
local sha = f:read(20)
tmp[i] = { sha = sha }
end
-- then the CRCs (assume ok, skip them)
for i=1, count do
local crc = f:read(4)
end
-- then come the offsets - read just the 32bit ones, does not handle packs > 2G
for i=1, count do
local offset = read_int(f)
tmp[i].offset = offset
end
-- construct the lookup table
local lookup = {}
for i=1, count do
lookup[tmp[i].sha] = tmp[i].offset
end
self.index = lookup
end
-- constructs the index/offsets if the index file is missing
function Pack:construct_index(path)
local index = {}
for i=1, self.nobjects do
local offset = self.offsets[i]
local data, len, type = self:read_object(offset)
local sha = object_sha(data, len, types[type])
index[binary_sha(sha)] = offset
end
self.index = index
end
function Pack:close()
self.pack_file:close()
end
function Pack.open(path)
local fp = assert(io.open(path, 'rb')) -- stays open
-- read the pack header
local head = fp:read(4)
assert(head == 'PACK', "Incorrect header: " .. head)
local version = read_int(fp)
assert(version == 2, "Incorrect version: " .. version)
local nobj = read_int(fp)
local pack = setmetatable({
offsets = {},
nobjects = nobj,
pack_file = fp,
}, Pack)
-- fill the offsets by traversing through the pack
for i=1,nobj do
pack.offsets[i] = fp:seek()
-- ignore the object data, we only need the offset in the pack
pack:read_object(nil, true)
end
-- read the index
local fi = io.open((path:gsub('%.pack$', '.idx')), 'rb')
if fi then
pack:parse_index(fi)
fi:close()
else
pack:construct_index(path)
end
return pack
end
return Pack

188
lualibs/git/protocol.lua Normal file
View File

@@ -0,0 +1,188 @@
local socket = require 'socket'
local urllib = require 'socket.url'
local lfs = require 'lfs'
local Repo = git.repo.Repo
local Pack = git.pack.Pack
local join_path = git.util.join_path
local parent_dir = git.util.parent_dir
local make_dir = git.util.make_dir
local correct_separators = git.util.correct_separators
local assert, error, getmetatable, io, os, pairs, print, require, string, tonumber =
assert, error, getmetatable, io, os, pairs, print, require, string, tonumber
local _VERSION, newproxy = _VERSION, newproxy
module(...)
local GIT_PORT = 9418
local function git_connect(host)
local sock = assert(socket.connect(host, GIT_PORT))
local gitsocket = {}
function gitsocket:send(data)
if not data then -- flush packet
sock:send('0000')
else
local len = #data + 4
len = string.format("%04x", len)
assert(sock:send(len .. data))
end
end
function gitsocket:receive()
local len = assert(sock:receive(4))
len = tonumber(len, 16)
if len == 0 then return end -- flush packet
local data = assert(sock:receive(len - 4))
return data
end
function gitsocket:close()
sock:close()
end
return gitsocket
end
local function addFinalizer(object, finalizer)
if _VERSION <= "Lua 5.1" then
local gc = newproxy(true)
getmetatable(gc).__gc = finalizer
object.__gc = gc
else
local mt = getmetatable(object)
if mt then mt.__gc = finalizer
else setmetatable(object, {__gc = finalizer})
end
end
end
local function git_fetch(host, path, repo, head, supress_progress)
local s = git_connect(host)
s:send('git-upload-pack '..path..'\0host='..host..'\0')
local refs, refsbyname = {}, {}
repeat
local ref = s:receive()
if ref then
local sha, name = ref:sub(1,40), ref:sub(42, -2)
refs[sha] = name
refsbyname[name] = sha
end
until not ref
local wantedSha
local headsha = head and refsbyname[head]
for sha, ref in pairs(refs) do
-- we implicitly want this ref
local wantObject = true
-- unless we ask for a specific head
if headsha then
if sha ~= headsha then
wantObject = false
else
wantedSha = sha
end
end
-- or we already have it
if repo and repo:has_object(sha) then
wantObject = false
end
if wantObject then
s:send('want '..sha..' multi_ack_detailed side-band-64k ofs-delta\n')
end
end
if head and not wantedSha then
error("Server does not have "..head)
end
s:send('deepen 1')
s:send()
while s:receive() do end
s:send('done\n')
assert(s:receive() == "NAK\n")
local packname = os.tmpname() .. '.pack'
local packfile = assert(io.open(packname, 'wb'))
repeat
local got = s:receive()
if got then
-- get sideband channel, 1=pack data, 2=progress, 3=error
local cmd = string.byte(got:sub(1,1))
local data = got:sub(2)
if cmd == 1 then
packfile:write(data)
elseif cmd == 2 then
if not supress_progress then io.write(data) end
else
error(data)
end
end
until not got
packfile:close()
s:close()
local pack = Pack.open(packname)
if repo then
pack:unpack(repo)
repo.isShallow = true
if wantedSha then
local headfile = correct_separators(join_path(repo.dir, head))
assert(make_dir(parent_dir(headfile)))
local f = assert(io.open(headfile, 'wb'))
f:write(wantedSha)
f:close()
end
end
addFinalizer(pack, function()
os.remove(packname)
end)
return pack, wantedSha
end
function fetch(url, repo, head, supress_progress)
if repo then assert(getmetatable(repo) == Repo, "arg #2 is not a repository") end
url = urllib.parse(url)
if url.scheme == 'git' then
local pack, sha = git_fetch(url.host, url.path, repo, head, supress_progress)
return pack, sha
else
error('unsupported scheme: '..url.scheme)
end
end
function remotes(url)
-- TODO: refactor common code
url = assert(urllib.parse(url))
if url.scheme ~= 'git' then
error('unsupported scheme: '..url.scheme)
end
local host, path = url.host, url.path
local s = git_connect(host)
s:send('git-upload-pack '..path..'\0host='..host..'\0')
local remote = {}
repeat
local ref = s:receive()
if ref then
local sha, name = ref:sub(1,40), ref:sub(42, -2)
remote[name] = sha
end
until not ref
s:close()
return remote
end

283
lualibs/git/repo.lua Normal file
View File

@@ -0,0 +1,283 @@
local util = require 'git.util'
local objects = require 'git.objects'
local core = require 'git.core'
local pack = require 'git.pack'
local join_path = util.join_path
local decompressed = util.decompressed
local read_until_nul = util.read_until_nul
local to_hex = util.to_hex
local object_sha = util.object_sha
local readable_sha = util.readable_sha
local deflate = core.deflate
local lfs = require 'lfs'
local assert, error, io, ipairs, print, os, setmetatable, string, table =
assert, error, io, ipairs, print, os, setmetatable, string, table
module(...)
Repo = {}
Repo.__index = Repo
-- retrieves an object identified by `sha` from the repository or its packs
-- returns a file-like object (supports 'read', 'seek' and 'close'), the size
-- of the object and its type
-- errors when the object does not exist
function Repo:raw_object(sha)
-- first, look in 'objects' directory
-- first byte of sha is the directory, the rest is name of object file
sha = readable_sha(sha)
local dir = sha:sub(1,2)
local file = sha:sub(3)
local path = join_path(self.dir, 'objects', dir, file)
if not lfs.attributes(path, 'size') then
-- then, try to look in packs
for _, pack in ipairs(self.packs) do
local obj, len, typ = pack:get_object(sha)
if obj then
return obj, len, typ
end
end
error('Object not found in object neither in packs: '..sha)
else
-- the objects are zlib compressed
local f = decompressed(path)
-- retrieve the type and length - <type> SP <len> \0 <data...>
local content = read_until_nul(f)
local typ, len = content:match('(%w+) (%d+)')
return f, len, typ
end
end
--- Store a new object into the repository in `objects` directory.
-- @param data A string containing the contents of the new file.
-- @param len The length of the data.
-- @param type One of 'commit', 'blob', 'tree', 'tag'
function Repo:store_object(data, len, type)
local sha = readable_sha(object_sha(data, len, type))
local dir = sha:sub(1,2)
local file = sha:sub(3)
util.make_dir(join_path(self.dir, 'objects', dir))
local path = join_path(self.dir, 'objects', dir, file)
local fo = assert(io.open(path, 'wb'))
local header = type .. ' ' .. len .. '\0'
local compressed = deflate()(header .. data, "finish")
fo:write(compressed)
fo:close()
end
local function resolvetag(f)
local tag
local line = f:read()
while line do
tag = line:match('^object (%x+)$')
if tag then break end
line = f:read()
end
f:close()
return tag
end
function Repo:commit(sha)
local f, len, typ = self:raw_object(sha)
while typ == 'tag' do
sha = assert(resolvetag(f), 'could not parse tag for '..readable_sha(sha))
f, len, typ = self:raw_object(sha)
end
assert(typ == 'commit', string.format('%s (%s) is not a commit', sha, typ))
local commit = { id = sha, repo = self, stored = true, parents = {} }
repeat
local line = f:read()
if not line then break end
local space = line:find(' ') or 0
local word = line:sub(1, space - 1)
local afterSpace = line:sub(space + 1)
if word == 'tree' then
commit.tree_sha = afterSpace
elseif word == 'parent' then
table.insert(commit.parents, afterSpace)
elseif word == 'author' then
commit.author = afterSpace
elseif word == 'committer' then
commit.committer = afterSpace
elseif commit.message then
table.insert(commit.message, line)
elseif line == '' then
commit.message = {}
end
until false -- ends with break
f:close()
commit.message = table.concat(commit.message, '\n')
return setmetatable(commit, objects.Commit)
end
function Repo:tree(sha)
local f, len, typ = self:raw_object(sha)
assert(typ == 'tree', string.format('%s (%s) is not a tree', sha, typ))
local tree = { id = sha, repo = self, stored = true, _entries = {} }
while true do
local info = read_until_nul(f)
if not info then break end
local entry_sha = to_hex(f:read(20))
local mode, name = info:match('^(%d+)%s(.+)$')
local entry_type = 'blob'
if mode == '40000' then
entry_type = 'tree'
elseif mode == '160000' then
entry_type = 'commit'
end
tree._entries[name] = { mode = mode, id = entry_sha, type = entry_type }
end
f:close()
return setmetatable(tree, objects.Tree)
end
-- retrieves a Blob
function Repo:blob(sha)
local f, len, typ = self:raw_object(sha)
f:close() -- can be reopened in Blob:content()
assert(typ == 'blob', string.format('%s (%s) is not a blob', sha, typ))
return setmetatable({
id = sha,
len = len,
repo = self,
stored = true }, objects.Blob)
end
function Repo:head()
return self:commit(self.refs.HEAD)
end
function Repo:has_object(sha)
local dir = sha:sub(1,2)
local file = sha:sub(3)
local path = join_path(self.dir, 'objects', dir, file)
if lfs.attributes(path, 'size') then return true end
for _, pack in ipairs(self.packs) do
local has = pack:has_object(sha)
if has then return true end
end
return false
end
function Repo:checkout(sha, target)
if not target then target = self.workDir end
assert(target, 'target directory not specified')
local commit = self:commit(sha)
commit:checkout(target)
-- if the repo was checked out using the deepen command (one level of history only)
-- mark the commit's parent as shalow, that is it has no history
if self.isShallow then
-- if it has a parent, mark it shallow
if commit.parents[1] then
local f = assert(io.open(self.dir .. '/shallow', "w"))
f:write(commit.parents[1], '\n')
f:close()
end
end
end
function Repo:close()
for _, pack in ipairs(self.packs) do
pack:close()
end
end
function create(dir)
if not dir:match('%.git.?$') then
dir = join_path(dir, '.git')
end
util.make_dir(dir)
util.make_dir(dir .. '/branches')
util.make_dir(dir .. '/hooks')
util.make_dir(dir .. '/info')
util.make_dir(dir .. '/objects/info')
util.make_dir(dir .. '/objects/pack')
util.make_dir(dir .. '/refs/heads')
util.make_dir(dir .. '/refs/tags')
util.make_dir(dir .. '/refs/remotes')
do
local f = assert(io.open(dir .. "/HEAD", "w"))
f:write("ref: refs/heads/master\n")
f:close()
end
local refs = {}
local packs = {}
return setmetatable({
dir = dir,
refs = refs,
packs = packs,
}, Repo)
end
-- opens a repository located in working directory `dir` or directly a .git repo
function open(dir)
local workDir = dir
if not dir:match('%.git.?$') then
dir = join_path(dir, '.git')
else
workDir = nil -- no working directory, working directly with repo
end
local refs = {}
for _,d in ipairs{'refs/heads', 'refs/tags'} do
for fn in lfs.dir(join_path(dir, d)) do
if fn ~= '.' and fn ~= '..' then
local path = join_path(dir, d, fn)
local f = assert(io.open(path), 'rb')
local ref = f:read()
refs[join_path(d, fn)] = ref
f:close()
end
end
end
local packs = {}
for fn in lfs.dir(join_path(dir, 'objects/pack')) do
if fn:match('%.pack$') then
local path = join_path(dir, 'objects/pack', fn)
table.insert(packs, pack.open(path))
end
end
local head = io.open(join_path(dir, 'HEAD'), 'rb')
if head then
local src = head:read()
local HEAD = src:match('ref: (.-)$')
refs.HEAD = refs[HEAD]
head:close()
end
return setmetatable({
dir = dir,
workDir = workDir,
refs = refs,
packs = packs,
}, Repo)
end
return Repo

233
lualibs/git/util.lua Normal file
View File

@@ -0,0 +1,233 @@
local lfs = require 'lfs'
local core = require 'git.core'
local deflate = core.deflate
local inflate = core.inflate
local sha = core.sha
module(..., package.seeall)
local BUF_SIZE = 4096
local dirsep = package.config:sub(1,1)
-- replaces '/' path separators on Windows with the correct ones ('\\')
function correct_separators(path)
return path:gsub('/', dirsep)
end
-- joins several path components into a single path, uses system-specific directory
-- separator, cleans input, i.e. join_path('a/', 'b', 'c/') => 'a/b/c'
function join_path(...)
local n = select('#', ...)
local args = {...}
for i=1,n do
args[i] = args[i]:gsub(dirsep..'?$', '')
end
return table.concat(args, dirsep, 1, n)
end
-- Return the path with the all occurences of '/.' or '\.' (representing
-- the current directory) removed.
local function remove_curr_dir_dots(path)
while path:match(dirsep .. "%." .. dirsep) do -- match("/%./")
path = path:gsub(dirsep .. "%." .. dirsep, dirsep) -- gsub("/%./", "/")
end
return path:gsub(dirsep .. "%.$", "") -- gsub("/%.$", "")
end
-- Return whether the path is a root.
local function is_root(path)
return path:find("^[%u%U.]?:?[/\\]$")
end
-- Return the path with the unnecessary trailing separator removed.
local function remove_trailing(path)
if path:sub(-1) == dirsep and not is_root(path) then path = path:sub(1,-2) end
return path
end
-- Extract file or directory name from its path.
local function extract_name(path)
if is_root(path) then return path end
path = remove_trailing(path)
path = path:gsub("^.*" .. dirsep, "")
return path
end
-- Return the string 'str', with all magic (pattern) characters escaped.
local function escape_magic(str)
local escaped = str:gsub('[%-%.%+%[%]%(%)%^%%%?%*%^%$]','%%%1')
return escaped
end
-- Return parent directory of the 'path' or nil if there's no parent directory.
-- If 'path' is a path to file, return the directory the file is in.
function parent_dir(path)
path = remove_curr_dir_dots(path)
path = remove_trailing(path)
local dir = path:gsub(escape_magic(extract_name(path)) .. "$", "")
if dir == "" then
return nil
else
return remove_trailing(dir)
end
end
-- Make a new directory, making also all of its parent directories that doesn't exist.
function make_dir(path)
if lfs.attributes(path) then
return true
else
local par_dir = parent_dir(path)
if par_dir then
assert(make_dir(par_dir))
end
return lfs.mkdir(path)
end
end
-- Reader class
-- adapted from Penlight: https://raw.github.com/stevedonovan/Penlight/master/lua/pl/stringio.lua
local SR = {}
SR.__index = SR
function SR:_read(fmt)
local i,str = self.i,self.str
local sz = #str
if i > sz then return nil, "past end of file" end
local res
if fmt == '*l' or fmt == '*L' then
local idx = str:find('\n',i) or (sz+1)
res = str:sub(i,fmt == '*l' and idx-1 or idx)
self.i = idx+1
elseif fmt == '*a' then
res = str:sub(i)
self.i = sz+1
elseif fmt == '*n' then
local _,i2,i2,idx
_,idx = str:find ('%s*%d+',i)
_,i2 = str:find ('^%.%d+',idx+1)
if i2 then idx = i2 end
_,i2 = str:find ('^[eE][%+%-]*%d+',idx+1)
if i2 then idx = i2 end
local val = str:sub(i,idx)
res = tonumber(val)
self.i = idx+1
elseif type(fmt) == 'number' then
res = str:sub(i,i+fmt-1)
self.i = i + fmt
else
error("bad read format",2)
end
return res
end
function SR:read(...)
if select('#',...) == 0 then
return self:_read('*l')
else
local res, fmts = {},{...}
for i = 1, #fmts do
res[i] = self:_read(fmts[i])
end
return unpack(res)
end
end
function SR:seek(whence,offset)
local base
whence = whence or 'cur'
offset = offset or 0
if whence == 'set' then
base = 1
elseif whence == 'cur' then
base = self.i
elseif whence == 'end' then
base = #self.str
end
self.i = base + offset
return self.i
end
function SR:close() -- for compatibility only
end
--- create a file-like object for reading from a given string.
-- @param s The input string.
function reader(s)
return setmetatable({str=s,i=1},SR)
end
-- decompress the file and return a handle to temporary uncompressed file
function decompressed(path)
local fi = assert(io.open(path, 'rb'))
local result = {}
local z = inflate()
repeat
local str = fi:read(BUF_SIZE)
local data = z(str)
if type(data) == 'string' then
result[#result+1] = data
else print('!!!', data) end
until not str
fi:close()
return reader(table.concat(result))
end
-- reads until the byte \0, consumes it and returns the string up to the \0
function read_until_nul(f)
local t = {}
repeat
local c = f:read(1)
if c and c ~= '\0' then t[#t+1] = c end
until not c or c == '\0'
if #t > 0 then
return table.concat(t)
else
return nil
end
end
-- converts a string to lowercase hex
function to_hex(s)
return (s:gsub('.', function(c)
return string.format('%02x', string.byte(c))
end))
end
-- converts a string from hex to binary
function from_hex(s)
return (s:gsub('..', function(cc)
return string.char(tonumber(cc, 16))
end))
end
-- always returns readable (hex) hash
function readable_sha(s)
if #s ~= 40 then return to_hex(s)
else return s end
end
-- always returns binary hash
function binary_sha(s)
if #s ~= 20 then return from_hex(s)
else return s end
end
function object_sha(data, len, type)
local header = type .. ' ' .. len .. '\0'
local res = sha(header .. data)
return res
end
function deflate(data)
local c = deflate()
return c(data, "finish")
end

746
lualibs/luadist.lua Normal file
View File

@@ -0,0 +1,746 @@
#!/usr/bin/env lua
-- Command line interface to LuaDist-git.
local dist = require "dist"
local utils = require "dist.utils"
local depends = require "dist.depends"
local package = require "dist.package"
local mf = require "dist.manifest"
local cfg = require "dist.config"
local sys = require "dist.sys"
-- CLI commands of Luadist.
local commands
commands = {
-- Print help for this command line interface.
["help"] = {
help = [[
Usage: luadist [DEPLOYMENT_DIRECTORY] <COMMAND> [ARGUMENTS...] [-VARIABLES...]
Commands:
help - print this help
install - install modules
remove - remove modules
refresh - update information about modules in repositories
list - list installed modules
info - show information about modules
search - search repositories for modules
fetch - download modules
make - manually deploy modules from local paths
upload - upload installed modules to their repositories
tree - print dependency tree of a module
selftest - run the selftest of LuaDist
To get help on specific command, run:
luadist help <COMMAND>
]],
run = function (deploy_dir, help_item)
deploy_dir = deploy_dir or dist.get_deploy_dir()
help_item = help_item or {}
assert(type(deploy_dir) == "string", "luadist.help: Argument 'deploy_dir' is not a string.")
assert(type(help_item) == "table", "luadist.help: Argument 'help_item' is not a table.")
deploy_dir = sys.abs_path(deploy_dir)
if not help_item or not commands[help_item[1]] then
help_item = "help"
else
help_item = help_item[1]
end
print_info()
print(commands[help_item].help)
return 0
end
},
-- Install modules.
["install"] = {
help = [[
Usage: luadist [DEPLOYMENT_DIRECTORY] install MODULES... [-VARIABLES...]
The 'install' command will install specified MODULES to
DEPLOYMENT_DIRECTORY. LuaDist will also automatically resolve, download
and install all dependencies.
If DEPLOYMENT_DIRECTORY is not specified, the deployment directory
of LuaDist is used.
You can use * (an asterisk sign) in the name of the module as a wildcard
with the meaning 'any symbols' (in most shells, the module name then must
be quoted to prevent the expansion of asterisk by the shell itself).
Optional CMake VARIABLES in -D format (e.g. -Dvariable=value) or LuaDist
configuration VARIABLES (e.g. -variable=value) can be specified.
The -simulate configuration option makes LuaDist only to simulate the
installation of modules (no modules will be really installed).
]],
run = function (deploy_dir, modules, cmake_variables)
deploy_dir = deploy_dir or dist.get_deploy_dir()
if type(modules) == "string" then modules = {modules} end
cmake_variables = cmake_variables or {}
assert(type(deploy_dir) == "string", "luadist.install: Argument 'deploy_dir' is not a string.")
assert(type(modules) == "table", "luadist.install: Argument 'modules' is not a string or table.")
assert(type(cmake_variables) == "table", "luadist.install: Argument 'cmake_variables' is not a table.")
deploy_dir = sys.abs_path(deploy_dir)
if cfg.simulate then
print("NOTE: this is just simulation.")
end
if #modules == 0 then
print("No modules to install specified.")
return 0
end
local ok, err = dist.install(modules, deploy_dir, cmake_variables)
if not ok then
print(err)
os.exit(1)
else
print((cfg.simulate and "Simulated installation" or "Installation") .. " successful.")
return 0
end
end
},
-- Remove modules.
["remove"] = {
help = [[
Usage: luadist [DEPLOYMENT_DIRECTORY] remove MODULES... [-VARIABLES...]
The 'remove' command will remove specified MODULES from
DEPLOYMENT_DIRECTORY. If no module is specified, all modules
will be removed.
If DEPLOYMENT_DIRECTORY is not specified, the deployment directory
of LuaDist is used. If no MODULES are specified, all installed modules
will be removed.
You can use * (an asterisk sign) in the name of the module as a wildcard
with the meaning 'any symbols' (in most shells, the module name then must
be quoted to prevent the expansion of asterisk by the shell itself).
Optional LuaDist configuration VARIABLES (e.g. -variable=value) can be
specified.
WARNING: dependencies between modules are NOT taken into account when
removing modules!
]],
run = function (deploy_dir, modules)
deploy_dir = deploy_dir or dist.get_deploy_dir()
if type(modules) == "string" then modules = {modules} end
assert(type(deploy_dir) == "string", "luadist.remove: Argument 'deploy_dir' is not a string.")
assert(type(modules) == "table", "luadist.remove: Argument 'modules' is not a string or table.")
deploy_dir = sys.abs_path(deploy_dir)
local num, err = dist.remove(modules, deploy_dir)
if not num then
print(err)
os.exit(1)
else
print("Removed modules: " .. num)
return 0
end
end
},
-- Update repositories.
["refresh"] = {
help = [[
Usage: luadist [DEPLOYMENT_DIRECTORY] refresh [-VARIABLES...]
The 'refresh' command will update information about modules in all software
repositories of specified DEPLOYMENT_DIRECTORY. Also, the cached dependency
manifest, built from previous installations or invocations of 'tree'
functionality will be deleted.
If DEPLOYMENT_DIRECTORY is not specified, the deployment directory
of LuaDist is used.
Optional LuaDist configuration VARIABLES (e.g. -variable=value) can be
specified.
]],
run = function (deploy_dir)
deploy_dir = deploy_dir or dist.get_deploy_dir()
assert(type(deploy_dir) == "string", "luadist.refresh: Argument 'deploy_dir' is not a string.")
deploy_dir = sys.abs_path(deploy_dir)
-- TODO: should be deleting the dep_manifest decoupled from refreshing the repository info?
-- delete cached dependency manifest
local dep_manifest_file = sys.abs_path(sys.make_path(deploy_dir, cfg.dep_cache_file))
local dep_mf_deleted = false
if sys.exists(dep_manifest_file) then
sys.delete(dep_manifest_file)
dep_mf_deleted = true
end
-- refresh repository information
local ok, err = dist.update_manifest(deploy_dir)
if not ok then
print(err)
os.exit(1)
else
print("Repositories successfuly updated" .. (dep_mf_deleted and " and dependency cache deleted" or "") .. ".")
return 0
end
end
},
-- Manually deploy modules.
["make"] = {
help = [[
Usage: luadist [DEPLOYMENT_DIRECTORY] make MODULE_PATHS... [-VARIABLES...]
The 'make' command will manually deploy modules from specified local
MODULE_PATHS into the DEPLOYMENT_DIRECTORY.
The MODULE_PATHS will be preserved. If DEPLOYMENT_DIRECTORY is not
specified, the deployment directory of LuaDist is used.
Optional CMake VARIABLES in -D format (e.g. -Dvariable=value) or LuaDist
configuration VARIABLES (e.g. -variable=value) can be specified.
The -simulate configuration option makes LuaDist only to simulate the
deployment of modules (no modules will be really deployed).
WARNING: this command does NOT check whether the dependencies of deployed
modules are satisfied or not!
]],
run = function (deploy_dir, module_paths, cmake_variables)
deploy_dir = deploy_dir or dist.get_deploy_dir()
module_paths = module_paths or {}
cmake_variables = cmake_variables or {}
assert(type(deploy_dir) == "string", "luadist.make: Argument 'deploy_dir' is not a string.")
assert(type(module_paths) == "table", "luadist.make: Argument 'module_paths' is not a table.")
assert(type(cmake_variables) == "table", "luadist.make: Argument 'cmake_variables' is not a table.")
deploy_dir = sys.abs_path(deploy_dir)
if cfg.simulate then
print("NOTE: this is just simulation.")
end
if #module_paths == 0 then
print("No module paths to deploy specified.")
return 0
end
local ok, err = dist.make(deploy_dir, module_paths, cmake_variables)
if not ok then
print(err)
os.exit(1)
end
print((cfg.simulate and "Simulated deployment" or "Deployment") .. " successful.")
return 0
end
},
-- Download modules.
["fetch"] = {
help = [[
Usage: luadist [FETCH_DIRECTORY] fetch MODULES... [-VARIABLES...]
The 'fetch' command will download specified MODULES to the FETCH_DIRECTORY.
If no FETCH_DIRECTORY is specified, the temporary directory of LuaDist
deployment directory (i.e. ']] .. cfg.temp_dir .. [[') is used.
If the version is not specified in module name, the most recent version
available will be downloaded.
Optional LuaDist configuration VARIABLES (e.g. -variable=value) can be
specified.
]],
run = function (fetch_dir, modules)
fetch_dir = fetch_dir or dist.get_deploy_dir()
modules = modules or {}
assert(type(fetch_dir) == "string", "luadist.fetch: Argument 'fetch_dir' is not a string.")
assert(type(modules) == "table", "luadist.fetch: Argument 'modules' is not a table.")
fetch_dir = sys.abs_path(fetch_dir)
-- if the default parameter (i.e. deploy_dir) is passed, use the default temp_dir
if fetch_dir == dist.get_deploy_dir() then
fetch_dir = sys.make_path(fetch_dir, cfg.temp_dir)
end
if #modules == 0 then
print("No modules to download specified.")
return 0
end
local ok, err = dist.fetch(modules, fetch_dir)
if not ok then
print(err)
os.exit(1)
else
print("Modules successfuly downloaded to '" .. fetch_dir .. "'.")
return 0
end
end
},
-- Upload modules.
["upload"] = {
help = [[
Usage: luadist [DEPLOYMENT_DIRECTORY] upload MODULES... [-VARIABLES...]
The 'upload' command will upload the binary versions of specified MODULES,
installed in the DEPLOYMENT_DIRECTORY, to their LuaDist repositories.
Base url of repositories is given by configuration variable 'upload_url'
(by default ']] .. cfg.upload_url .. [[') which you can change.
E.g.: Binary version of module 'lua', installed in DEPLOYMENT_DIRECTORY,
will now be uploaded to repository ']] .. cfg.upload_url .. [[lua.git'.
Organization of uploaded modules and their repositories is subject
to the conventions described in more detail in the source code
of the 'dist.upload_modules()' function (file 'dist/init.lua').
If DEPLOYMENT_DIRECTORY is not specified, the deployment directory
of LuaDist is used. If no MODULES are specified, all installed modules
will be uploaded.
You can use * (an asterisk sign) in the name of the module as a wildcard
with the meaning 'any symbols' (in most shells, the module name then must
be quoted to prevent the expansion of asterisk by the shell itself).
Optional LuaDist configuration VARIABLES (e.g. -variable=value) can be
specified.
]],
run = function (deploy_dir, modules)
-- check if we have git
local ok = utils.system_dependency_available("git", "git --version")
if not ok then os.exit(1) end
deploy_dir = deploy_dir or dist.get_deploy_dir()
if type(modules) == "string" then modules = {modules} end
assert(type(deploy_dir) == "string", "luadist.upload: Argument 'deploy_dir' is not a string.")
assert(type(modules) == "table", "luadist.upload: Argument 'modules' is not a string or table.")
deploy_dir = sys.abs_path(deploy_dir)
local num, err = dist.upload_modules(deploy_dir, modules, cfg.upload_url)
if not num then
print(err)
os.exit(1)
else
print("Uploaded modules: " .. num)
return 0
end
end
},
-- List installed modules.
["list"] = {
help = [[
Usage: luadist [DEPLOYMENT_DIRECTORY] list [STRINGS...] [-VARIABLES...]
The 'list' command will list all modules installed in specified
DEPLOYMENT_DIRECTORY, which contain one or more optional STRINGS.
If DEPLOYMENT_DIRECTORY is not specified, the deployment directory
of LuaDist is used. If STRINGS are not specified, all installed modules
are listed.
Optional LuaDist configuration VARIABLES (e.g. -variable=value) can be
specified.
]],
run = function (deploy_dir, strings)
deploy_dir = deploy_dir or dist.get_deploy_dir()
strings = strings or {}
assert(type(deploy_dir) == "string", "luadist.list: Argument 'deploy_dir' is not a string.")
assert(type(strings) == "table", "luadist.list: Argument 'strings' is not a table.")
deploy_dir = sys.abs_path(deploy_dir)
local deployed = dist.get_deployed(deploy_dir)
deployed = depends.filter_packages_by_strings(deployed, strings)
print("\nInstalled modules:")
print("==================\n")
for _, pkg in pairs(deployed) do
print(" " .. pkg.name .. "-" .. pkg.version .. "\t(" .. pkg.arch .. "-" .. pkg.type .. ")" .. (pkg.provided_by and "\t [provided by " .. pkg.provided_by .. "]" or ""))
end
print()
return 0
end
},
-- Search for modules in repositories.
["search"] = {
help = [[
Usage: luadist [DEPLOYMENT_DIRECTORY] search [STRINGS...] [-VARIABLES...]
The 'search' command will list all modules from repositories, which contain
one or more STRINGS.
If no STRINGS are specified, all available modules are listed.
Optional LuaDist configuration VARIABLES (e.g. -variable=value) can be
specified.
]],
run = function (deploy_dir, strings)
deploy_dir = deploy_dir or dist.get_deploy_dir()
strings = strings or {}
assert(type(deploy_dir) == "string", "luadist.search: Argument 'deploy_dir' is not a string.")
assert(type(strings) == "table", "luadist.search: Argument 'strings' is not a table.")
deploy_dir = sys.abs_path(deploy_dir)
local available, err = mf.get_manifest()
if not available then
print(err)
os.exit(1)
end
available = depends.filter_packages_by_strings(available, strings)
available = depends.sort_by_names(available)
print("\nModules found:")
print("==============\n")
for _, pkg in pairs(available) do
print(" " .. pkg.name)
end
print()
return 0
end
},
-- Show information about modules.
["info"] = {
help = [[
Usage: luadist [DEPLOYMENT_DIRECTORY] info [MODULES...] [-VARIABLES...]
The 'info' command shows information about specified modules from
repositories. This command also shows whether modules are installed
in DEPLOYMENT_DIRECTORY.
If no MODULES are specified, all available modules are shown.
If DEPLOYMENT_DIRECTORY is not specified, the deployment directory
of LuaDist is used.
Optional LuaDist configuration VARIABLES (e.g. -variable=value) can be
specified.
]],
run = function (deploy_dir, modules)
deploy_dir = deploy_dir or dist.get_deploy_dir()
modules = modules or {}
assert(type(deploy_dir) == "string", "luadist.info: Argument 'deploy_dir' is not a string.")
assert(type(modules) == "table", "luadist.info: Argument 'modules' is not a table.")
deploy_dir = sys.abs_path(deploy_dir)
local manifest, err = mf.get_manifest()
if not manifest then
print(err)
os.exit(1)
end
-- if no packages specified explicitly, show just info from .gitmodules for all packages available
if #modules == 0 then
modules = manifest
modules = depends.sort_by_names(modules)
local deployed = dist.get_deployed(deploy_dir)
print("")
for _, pkg in pairs(modules) do
print(" " .. pkg.name)
print(" Repository url: " .. (pkg.path or "N/A"))
print()
end
return 0
-- if some packages explicitly specified, retrieve and show detailed info about them
else
if #modules > 5 then
print("NOTE: More than 5 modules specified - operation may take a longer time.")
end
local deployed = dist.get_deployed(deploy_dir)
for _, module in pairs(modules) do
manifest, err = package.get_versions_info(module, manifest, deploy_dir, deployed)
if not manifest then
print(err)
os.exit(1)
end
end
modules = depends.find_packages(modules, manifest)
modules = depends.sort_by_names(modules)
print("")
for _, pkg in pairs(modules) do
print(" " .. pkg.name .. "-" .. pkg.version .. " (" .. pkg.arch .. "-" .. pkg.type ..")" .. (pkg.from_installed and " [info taken from installed version]" or ""))
print(" Description: " .. (pkg.desc or "N/A"))
print(" Author: " .. (pkg.author or "N/A"))
print(" Homepage: " .. (pkg.url or "N/A"))
print(" License: " .. (pkg.license or "N/A"))
print(" Repository url: " .. (pkg.path or "N/A"))
print(" Maintainer: " .. (pkg.maintainer or "N/A"))
if pkg.provides then print(" Provides: " .. utils.table_tostring(pkg.provides)) end
if pkg.depends then print(" Depends: " .. utils.table_tostring(pkg.depends)) end
if pkg.conflicts then print(" Conflicts: " .. utils.table_tostring(pkg.conflicts)) end
print(" State: " .. (depends.is_installed(pkg.name, deployed, pkg.version) and "installed" or "not installed"))
print()
end
return 0
end
end
},
-- Print dependency tree.
["tree"] = {
help = [[
Usage: luadist [DEPLOYMENT_DIRECTORY] tree [MODULES...] [-VARIABLES...]
The 'tree' command prints dependency tree for specified modules.
If no MODULES are specified, trees for all available modules are printed.
This information about modules is being cached in dependency manifest.
Optional LuaDist configuration VARIABLES (e.g. -variable=value) can be
specified.
]],
run = function (deploy_dir, modules)
deploy_dir = deploy_dir or dist.get_deploy_dir()
modules = modules or {}
assert(type(deploy_dir) == "string", "luadist.info: Argument 'deploy_dir' is not a string.")
assert(type(modules) == "table", "luadist.info: Argument 'modules' is not a table.")
deploy_dir = sys.abs_path(deploy_dir)
local manifest, err = mf.get_manifest()
if not manifest then
print(err)
os.exit(1)
end
-- if no modules specified explicitly, assume all modules
if #modules == 0 then modules = depends.sort_by_names(manifest) end
print("Getting dependency information... (this may take a lot of time)")
for _, module in pairs(modules) do
-- if all modules are being queried, extract the name
if type(module) == "table" then module = module.name end
local dep_manifest, err = dist.dependency_info(module, deploy_dir)
if not dep_manifest then
print(err)
os.exit(1)
else
-- print the dependency tree
local heading = "Dependency tree for '" .. module .. "' (on " .. cfg.arch .. "-" .. cfg.type .. "):"
print("\n" .. heading .. "")
print(string.rep("=", #heading) .. "\n")
for _, pkg in pairs(dep_manifest) do
local pkg_version, pkg_tag = pkg.version, pkg.version
if pkg.was_scm_version then
pkg_version, pkg_tag = "scm", "HEAD"
end
print(" " .. pkg.name .. "-" .. pkg_version .. " (" .. pkg.path .. ", " .. pkg_tag .. ")")
if pkg.depends then
for _, dep in pairs(pkg.depends) do
if type(dep) ~= "table" then
local found = depends.sort_by_versions(depends.find_packages(dep, dep_manifest))[1]
if not found then
print("Could not find the dependency '" .. dep .. "' in the dependency manifest.")
os.exit(1)
end
print(" * " .. found.name .. "-" .. found.version .. " (" .. found.path .. ", " .. found.version .. ")")
end
end
end
print()
end
end
end
return 0
end
},
-- Selftest of LuaDist.
["selftest"] = {
help = [[
Usage: luadist [TEST_DIRECTORY] selftest [-VARIABLES...]
The 'selftest' command runs tests of LuaDist, located in TEST_DIRECTORY and
displays the results.
If no TEST_DIRECTORY is specified, the default test directory of LuaDist
deployment directory (i.e. ']] .. cfg.test_dir .. [[') is used.
Optional LuaDist configuration VARIABLES (e.g. -variable=value) can be
specified.
]],
run = function (test_dir)
test_dir = test_dir or dist.get_deploy_dir()
assert(type(test_dir) == "string", "luadist.selftest: Argument 'deploy_dir' is not a string.")
test_dir = sys.abs_path(test_dir)
-- if the default parameter (i.e. deploy_dir) is passed, use the default test_dir
if test_dir == dist.get_deploy_dir() then
test_dir = sys.make_path(test_dir, cfg.test_dir)
end
-- try to get an iterator over test files and check it
local test_iterator, err = sys.get_directory(test_dir)
if not test_iterator then
print("Running tests from '" .. test_dir .. "' failed: " .. err)
os.exit(1)
end
-- run the tests
print("\nRunning tests:")
print("==============")
for test_file in sys.get_directory(test_dir) do
test_file = sys.make_path(test_dir, test_file)
if sys.is_file(test_file) then
print()
print(sys.extract_name(test_file) .. ":")
dofile(test_file)
end
end
print()
return 0
end
},
}
-- Run the functionality of LuaDist 'command' in the 'deploy_dir' with other items
-- or settings/variables starting at 'other_idx' index of special variable 'arg'.
local function run_command(deploy_dir, command, other_idx)
deploy_dir = deploy_dir or dist.get_deploy_dir()
assert(type(deploy_dir) == "string", "luadist.run_command: Argument 'deploy_dir' is not a string.")
assert(type(command) == "string", "luadist.run_command: Argument 'command' is not a string.")
assert(not other_idx or type(other_idx) == "number", "luadist.run_command: Argument 'other_idx' is not a number.")
deploy_dir = sys.abs_path(deploy_dir)
local items = {}
local cmake_variables = {}
-- parse items after the command (and LuaDist or CMake variables)
if other_idx then
for i = other_idx, #arg do
-- CMake variable
if arg[i]:match("^%-D(.-)=(.*)$") then
local variable, value = arg[i]:match("^%-D(.-)=(.*)$")
cmake_variables[variable] = value
-- LuaDist variable
elseif arg[i]:match("^%-(.-)=(.*)$") then
local variable, value = arg[i]:match("^%-(.-)=(.*)$")
apply_settings(variable, value)
-- LuaDist boolean variable with implicit 'true' value
elseif arg[i]:match("^%-(.-)$") then
local variable, value = arg[i]:match("^%-(.-)$")
apply_settings(variable, "true")
-- not a LuaDist or CMake variable
else
table.insert(items, arg[i])
end
end
end
-- run the required LuaDist functionality
return commands[command].run(sys.abs_path(deploy_dir), items, cmake_variables)
end
-- Print information about Luadist (version, license, etc.).
function print_info()
print([[
LuaDist-git ]].. cfg.version .. [[ - Lua package manager for the LuaDist deployment system.
Released under the MIT License. See https://github.com/luadist/luadist-git
]])
return 0
end
-- Convenience function for printing the main luadist help.
function print_help()
return run_command(nil, "help")
end
-- Set the LuaDist 'variable' to the 'value'.
-- See available settings in 'dist.config' module.
function apply_settings(variable, value)
assert(type(variable) == "string", "luadist.apply_settings: Argument 'variable' is not a string.")
assert(type(value) == "string", "luadist.apply_settings: Argument 'value' is not a string.")
-- check whether the settings variable exists
if cfg[variable] == nil then
print("Unknown LuaDist configuration option: '" .. variable .. "'.")
os.exit(1)
-- ensure the right type
elseif type(cfg[variable]) == "boolean" then
value = value:lower()
if value == "true" or value == "yes" or value == "on" or value == "1" then
value = true
elseif value == "false" or value == "no" or value == "off" or value == "0" then
value = false
else
print("Value of LuaDist option '" .. variable .. "' must be a boolean.")
os.exit(1)
end
elseif type(cfg[variable]) == "number" then
value = tonumber(value)
if not value then
print("Value of LuaDist option '" .. variable .. "' must be a number.")
os.exit(1)
end
elseif type(cfg[variable]) == "table" then
local err
value, err = utils.make_table(value, ",")
if not value then
print("Error when parsing the LuaDist variable '" .. variable .. "': " .. err)
os.exit(1)
end
end
-- set the LuaDist variable
cfg[variable] = value
end
-- Parse command line input and run the required command.
if pcall(debug.getlocal, 4, 1) then
return commands -- return commands when used as module
elseif not commands[arg[1]] and commands[arg[2]] then
-- deploy_dir specified
return run_command(arg[1], arg[2], 3)
elseif commands[arg[1]] then
-- deploy_dir not specified
return run_command(dist.get_deploy_dir(), arg[1], 2)
else
-- unknown command
if arg[1] then
print("Unknown command '" .. arg[1] .. "'. Printing help...\n")
print_help()
os.exit(1)
end
return print_help()
end

View File

@@ -58,7 +58,7 @@ function parser_metatable.__call (parser, lx, ...)
-- lexstream.
-- Since the error is rethrown, these places are stacked.
error (string.format ("%s\n - (l.%s, c.%s, k.%s) in parser %s",
ast :strmatch "gg.lua:%d+: (.*)" or ast,
ast:match "gg.lua:%d+: (.*)" or ast,
li[1], li[2], li[3], parser.name or parser.kind))
end
end

View File

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

View File

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

View File

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

View File

@@ -1,39 +1,46 @@
--
-- MobDebug 0.542
-- Copyright 2011-13 Paul Kulchenko
-- MobDebug 0.5511
-- Copyright 2011-14 Paul Kulchenko
-- Based on RemDebug 1.0 Copyright Kepler Project 2005
--
-- use loaded modules or load explicitly on those systems that require that
local require = require
local io = io or require "io"
local table = table or require "table"
local string = string or require "string"
local coroutine = coroutine or require "coroutine"
-- protect require "os" as it may fail on embedded systems without os module
local os = os or (function(module)
local ok, res = pcall(require, module)
return ok and res or nil
end)("os")
local mobdebug = {
_NAME = "mobdebug",
_VERSION = 0.542,
_VERSION = 0.5511,
_COPYRIGHT = "Paul Kulchenko",
_DESCRIPTION = "Mobile Remote Debugger for the Lua programming language",
port = os and os.getenv and os.getenv("MOBDEBUG_PORT") or 8172,
port = os and os.getenv and tonumber(os.getenv("MOBDEBUG_PORT")) or 8172,
checkcount = 200,
yieldtimeout = 0.02,
}
local coroutine = coroutine
local error = error
local getfenv = getfenv
local setfenv = setfenv
local loadstring = loadstring or load -- "load" replaced "loadstring" in Lua 5.2
local io = io
local os = os
local pairs = pairs
local require = require
local setmetatable = setmetatable
local string = string
local tonumber = tonumber
local unpack = table.unpack or unpack
local rawget = rawget
-- if strict.lua is used, then need to avoid referencing some global
-- variables, as they can be undefined;
-- use rawget to to avoid complaints from strict.lua at run-time.
-- use rawget to avoid complaints from strict.lua at run-time.
-- it's safe to do the initialization here as all these variables
-- should get defined values (of any) before the debugging starts.
-- should get defined values (if any) before the debugging starts.
-- there is also global 'wx' variable, which is checked as part of
-- the debug loop as 'wx' can be loaded at any time during debugging.
local genv = _G or _ENV
@@ -61,11 +68,12 @@ end
-- check for OS and convert file names to lower case on windows
-- (its file system is case insensitive, but case preserving), as setting a
-- breakpoint on x:\Foo.lua will not work if the file was loaded as X:\foo.lua.
-- OSX and Windows behave the same way (case insensitive, but case preserving)
local iscasepreserving = os and os.getenv and (os.getenv('WINDIR')
or (os.getenv('OS') or ''):match('[Ww]indows')
or os.getenv('DYLD_LIBRARY_PATH'))
or not io.open("/proc")
-- OSX and Windows behave the same way (case insensitive, but case preserving).
-- OSX can be configured to be case-sensitive, so check for that. This doesn't
-- handle the case of different partitions having different case-sensitivity.
local win = os and os.getenv and (os.getenv('WINDIR') or (os.getenv('OS') or ''):match('[Ww]indows')) and true or false
local mac = not win and (os and os.getenv and os.getenv('DYLD_LIBRARY_PATH') or not io.open("/proc")) and true or false
local iscasepreserving = win or (mac and io.open('/library') ~= nil)
-- turn jit off based on Mike Pall's comment in this discussion:
-- http://www.freelists.org/post/luajit/Debug-hooks-and-JIT,2
@@ -97,7 +105,7 @@ local outputs = {}
local iobase = {print = print}
local basedir = ""
local deferror = "execution aborted at default debugee"
local debugee = function ()
local debugee = function ()
local a = 1
for _ = 1, 10 do a = a + 1 end
error(deferror)
@@ -105,7 +113,7 @@ end
local function q(s) return s:gsub('([%(%)%.%%%+%-%*%?%[%^%$%]])','%%%1') end
local serpent = (function() ---- include Serpent module for serialization
local n, v = "serpent", 0.25 -- (C) 2012-13 Paul Kulchenko; MIT License
local n, v = "serpent", 0.272 -- (C) 2012-13 Paul Kulchenko; MIT License
local c, d = "Paul Kulchenko", "Lua serializer and pretty printer"
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, cdata = true}
@@ -115,7 +123,7 @@ for _,k in ipairs({'and', 'break', 'do', 'else', 'elseif', 'end', 'false',
'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
for k,v in pairs(G[g] or {}) do globals[v] = g..'.'..k end end
local function s(t, opts)
local name, indent, fatal, maxnum = opts.name, opts.indent, opts.fatal, opts.maxnum
@@ -137,13 +145,13 @@ local function s(t, opts)
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(k, o, n) -- k=keys, o=originaltable, n=padding
local alphanumsort = type(opts.sortkeys) == 'function' and opts.sortkeys or function(k, o, n) -- k=keys, o=originaltable, n=padding
local maxn, to = tonumber(n) or 12, {number = 'a', string = 'b'}
local function padnum(d) return ("%0"..maxn.."d"):format(d) end
table.sort(k, function(a,b)
-- sort numeric keys first: k[key] is non-nil for numeric keys
return (k[a] and 0 or to[type(a)] or 'z')..(tostring(a):gsub("%d+",padnum))
< (k[b] and 0 or to[type(b)] or 'z')..(tostring(b):gsub("%d+",padnum)) end) end
-- sort numeric keys first: k[key] is not nil for numerical keys
return (k[a] ~= nil and 0 or to[type(a)] or 'z')..(tostring(a):gsub("%d+",padnum))
< (k[b] ~= nil and 0 or to[type(b)] or 'z')..(tostring(b):gsub("%d+",padnum)) end) end
local function val2str(t, name, indent, insref, path, plainindex, level)
local ttype, level, mt = type(t), (level or 0), getmetatable(t)
local spath, sname = safename(path, name)
@@ -199,7 +207,7 @@ local function s(t, opts)
seen[t] = insref or spath
local ok, res = pcall(string.dump, t)
local func = ok and ((opts.nocode and "function() --[[..skipped..]] end" or
"loadstring("..safestr(res)..",'@serialized')")..comment(t, level))
"((loadstring or load)("..safestr(res)..",'@serialized'))")..comment(t, level))
return tag..(func or globerr(t, level))
else return tag..safestr(t) end -- handle all other types
end
@@ -210,13 +218,34 @@ local function s(t, opts)
return not name and body..warn or "do local "..body..sepr..tail.."return "..name..sepr.."end"
end
local function deserialize(data, opts)
local f, res = (loadstring or load)('return '..data)
if not f then f, res = (loadstring or load)(data) end
if not f then return f, res end
if opts and opts.safe == false then return pcall(f) end
local count, thread = 0, coroutine.running()
local h, m, c = debug.gethook(thread)
debug.sethook(function (e, l) count = count + 1
if count >= 3 then error("cannot call functions") end
end, "c")
local res = {pcall(f)}
count = 0 -- set again, otherwise it's tripped on the next sethook
debug.sethook(thread, h, m, c)
return (table.unpack or unpack)(res)
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,
load = deserialize,
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
mobdebug.line = serpent.line
mobdebug.dump = serpent.dump
local function removebasedir(path, basedir)
if iscasepreserving then
-- check if the lowercased path matches the basedir
@@ -487,7 +516,7 @@ local function debug_hook(event, line)
-- this is either a file name coming from loadstring("chunk", "file"),
-- or the actual source code that needs to be serialized (as it may
-- include newlines); assume it's a file name if it's all on one line.
file = file:find("[\r\n]") and serpent.line(file) or file
file = file:find("[\r\n]") and mobdebug.line(file) or file
end
-- set to true if we got here; this only needs to be done once per
@@ -513,7 +542,9 @@ local function debug_hook(event, line)
-- 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)
-- when coroutine.running() return `nil` (main thread in Lua 5.1),
-- step_over will equal 'main', so need to check for that explicitly.
or (step_over and step_over == (coroutine.running() or 'main') and stack_level <= step_level)
or has_breakpoint(file, line)
or is_pending(server))
@@ -538,7 +569,7 @@ local function debug_hook(event, line)
-- 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); return end
if abort == nil and res == "exit" then os.exit(1, true); return 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
@@ -548,6 +579,9 @@ local function debug_hook(event, line)
end
if vars then restore_vars(vars) end
-- last command requested Step Over/Out; store the current thread
if step_over == true then step_over = coroutine.running() or 'main' end
end
end
@@ -556,13 +590,13 @@ local function stringify_results(status, ...)
local t = {...}
for i,v in pairs(t) do -- stringify each of the returned values
local ok, res = pcall(serpent.line, v, {nocode = true, comment = 1})
local ok, res = pcall(mobdebug.line, v, {nocode = true, comment = 1})
t[i] = ok and res or ("%q"):format(res):gsub("\010","n"):gsub("\026","\\026")
end
-- stringify table with all returned values
-- this is done to allow each returned value to be used (serialized or not)
-- intependently and to preserve "original" comments
return pcall(serpent.dump, t, {sparse = false})
return pcall(mobdebug.dump, t, {sparse = false})
end
local function debugger_loop(sev, svars, sfile, sline)
@@ -629,7 +663,7 @@ local function debugger_loop(sev, svars, sfile, sline)
end
elseif command == "EXEC" then
local _, _, chunk = string.find(line, "^[A-Z]+%s+(.+)$")
if chunk then
if chunk then
local func, res = loadstring(chunk)
local status
if func then
@@ -687,13 +721,13 @@ local function debugger_loop(sev, svars, sfile, sline)
end
elseif command == "SETW" then
local _, _, exp = string.find(line, "^[A-Z]+%s+(.+)%s*$")
if exp then
if exp then
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")
server:send("200 OK " .. newidx .. "\n")
else
server:send("401 Error in Expression " .. #res .. "\n")
server:send(res)
@@ -745,8 +779,8 @@ local function debugger_loop(sev, svars, sfile, sline)
elseif command == "OVER" or command == "OUT" then
server:send("200 OK\n")
step_over = true
-- OVER and OUT are very similar except for
-- OVER and OUT are very similar except for
-- the stack level value at which to stop
if command == "OUT" then step_level = stack_level - 1
else step_level = stack_level end
@@ -788,7 +822,7 @@ local function debugger_loop(sev, svars, sfile, sline)
server:send("401 Error in Execution " .. #vars .. "\n")
server:send(vars)
else
local ok, res = pcall(serpent.dump, vars, {nocode = true, sparse = false})
local ok, res = pcall(mobdebug.dump, vars, {nocode = true, sparse = false})
if ok then
server:send("200 OK " .. res .. "\n")
else
@@ -800,19 +834,22 @@ local function debugger_loop(sev, svars, sfile, sline)
local _, _, stream, mode = string.find(line, "^[A-Z]+%s+(%w+)%s+([dcr])%s*$")
if stream and mode and stream == "stdout" then
-- assign "print" in the global environment
genv.print = mode == 'd' and iobase.print or coroutine.wrap(function(...)
local default = mode == 'd'
genv.print = default and iobase.print or coroutine.wrap(function()
-- wrapping into coroutine.wrap protects this function from
-- being stepped through in the debugger
local tbl = {...}
-- being stepped through in the debugger.
-- don't use vararg (...) as it adds a reference for its values,
-- which may affect how they are garbage collected
while true do
local tbl = {coroutine.yield()}
if mode == 'c' then iobase.print(unpack(tbl)) end
for n = 1, #tbl do
tbl[n] = select(2, pcall(serpent.line, tbl[n], {nocode = true, comment = false})) end
tbl[n] = select(2, pcall(mobdebug.line, tbl[n], {nocode = true, comment = false})) end
local file = table.concat(tbl, "\t").."\n"
server:send("204 Output " .. stream .. " " .. #file .. "\n" .. file)
tbl = {coroutine.yield()}
end
end)
if not default then genv.print() end -- "fake" print to start printing loop
server:send("200 OK\n")
else
server:send("400 Bad Request\n")
@@ -1008,7 +1045,7 @@ local function off()
end
end
-- Handles server debugging commands
-- Handles server debugging commands
local function handle(params, client, options)
local _, _, command = string.find(params, "^([a-z]+)")
local file, line, watch_idx
@@ -1021,7 +1058,7 @@ local function handle(params, client, options)
local breakpoint = client:receive()
if not breakpoint then
print("Program finished")
os.exit()
os.exit(0, true)
return -- use return here for those cases where os.exit() is not wanted
end
local _, _, status = string.find(breakpoint, "^(%d+)")
@@ -1051,12 +1088,12 @@ local function handle(params, client, options)
if size then
local msg = client:receive(tonumber(size))
print("Error in remote application: " .. msg)
os.exit(1)
os.exit(1, true)
return nil, nil, msg -- use return here for those cases where os.exit() is not wanted
end
else
print("Unknown error")
os.exit(1)
os.exit(1, true)
-- use return here for those cases where os.exit() is not wanted
return nil, nil, "Debugger error: unexpected response '" .. breakpoint .. "'"
end
@@ -1109,7 +1146,7 @@ local function handle(params, client, options)
file = removebasedir(file, basedir)
end
client:send("DELB " .. file .. " " .. line .. "\n")
if client:receive() == "200 OK" then
if client:receive() == "200 OK" then
remove_breakpoint(file, line)
else
print("Error: breakpoint not removed")
@@ -1132,7 +1169,7 @@ local function handle(params, client, options)
local _, _, index = string.find(params, "^[a-z]+%s+(%d+)%s*$")
if index then
client:send("DELW " .. index .. "\n")
if client:receive() == "200 OK" then
if client:receive() == "200 OK" then
watches[index] = nil
else
print("Error: watch expression not removed")
@@ -1143,17 +1180,17 @@ local function handle(params, client, options)
elseif command == "delallw" then
for index, exp in pairs(watches) do
client:send("DELW " .. index .. "\n")
if client:receive() == "200 OK" then
if client:receive() == "200 OK" then
watches[index] = nil
else
print("Error: watch expression at index " .. index .. " [" .. exp .. "] not removed")
end
end
elseif command == "eval" or command == "exec"
end
elseif command == "eval" or command == "exec"
or command == "load" or command == "loadstring"
or command == "reload" then
local _, _, exp = string.find(params, "^[a-z]+%s+(.+)$")
if exp or (command == "reload") then
if exp or (command == "reload") then
if command == "eval" or command == "exec" then
exp = (exp:gsub("%-%-%[(=*)%[.-%]%1%]", "") -- remove comments
:gsub("%-%-.-\n", " ") -- remove line comments
@@ -1175,9 +1212,10 @@ local function handle(params, client, options)
-- 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")
local shortp = winapi.short_path(exp)
file = shortp and io.open(shortp, "r")
end
if not file then error("Cannot open file " .. exp) end
if not file then return nil, nil, "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()
@@ -1252,7 +1290,7 @@ local function handle(params, client, options)
elseif command == "listw" then
for i, v in pairs(watches) do
print("Watch exp. " .. i .. ": " .. v)
end
end
elseif command == "suspend" then
client:send("SUSPEND\n")
elseif command == "stack" then
@@ -1271,7 +1309,7 @@ local function handle(params, client, options)
return nil, nil, stack
end
for _,frame in ipairs(stack) do
print(serpent.line(frame[1], {comment = false}))
print(mobdebug.line(frame[1], {comment = false}))
end
return stack
elseif status == "401" then
@@ -1443,6 +1481,8 @@ local function done()
end
-- make public functions available
mobdebug.setbreakpoint = set_breakpoint
mobdebug.removebreakpoint = remove_breakpoint
mobdebug.listen = listen
mobdebug.loop = loop
mobdebug.scratchpad = scratchpad
@@ -1454,8 +1494,6 @@ mobdebug.off = off
mobdebug.moai = moai
mobdebug.coro = coro
mobdebug.done = done
mobdebug.line = serpent.line
mobdebug.dump = serpent.dump
mobdebug.yield = nil -- callback
-- this is needed to make "require 'modebug'" to work when mobdebug

239
lualibs/sha2.lua Normal file
View File

@@ -0,0 +1,239 @@
-- SHA-256 code in Lua 5.2; based on the pseudo-code from
-- Wikipedia (http://en.wikipedia.org/wiki/SHA-2)
-- from http://lua-users.org/wiki/SecureHashAlgorithm
local band, rrotate, bxor, rshift, bnot =
bit32.band, bit32.rrotate, bit32.bxor, bit32.rshift, bit32.bnot
local string, setmetatable, assert = string, setmetatable, assert
-- Initialize table of round constants
-- (first 32 bits of the fractional parts of the cube roots of the first
-- 64 primes 2..311):
local k = {
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
}
-- transform a string of bytes in a string of hexadecimal digits
local function str2hexa (s)
local h = string.gsub(s, ".", function(c)
return string.format("%02x", string.byte(c))
end)
return h
end
-- transform number 'l' in a big-endian sequence of 'n' bytes
-- (coded as a string)
local function num2s (l, n)
local s = ""
for i = 1, n do
local rem = l % 256
s = string.char(rem) .. s
l = (l - rem) / 256
end
return s
end
-- transform the big-endian sequence of four bytes starting at
-- index 'i' in 's' into a number
local function s232num (s, i)
local n = 0
for i = i, i + 3 do
n = n*256 + string.byte(s, i)
end
return n
end
-- append the bit '1' to the message
-- append k bits '0', where k is the minimum number >= 0 such that the
-- resulting message length (in bits) is congruent to 448 (mod 512)
-- append length of message (before pre-processing), in bits, as 64-bit
-- big-endian integer
local function preproc (msg, len)
local extra = 64 - ((len + 1 + 8) % 64)
len = num2s(8 * len, 8) -- original len in bits, coded
msg = msg .. "\128" .. string.rep("\0", extra) .. len
assert(#msg % 64 == 0)
return msg
end
local function initH224 (H)
-- (second 32 bits of the fractional parts of the square roots of the
-- 9th through 16th primes 23..53)
H[1] = 0xc1059ed8
H[2] = 0x367cd507
H[3] = 0x3070dd17
H[4] = 0xf70e5939
H[5] = 0xffc00b31
H[6] = 0x68581511
H[7] = 0x64f98fa7
H[8] = 0xbefa4fa4
return H
end
local function initH256 (H)
-- (first 32 bits of the fractional parts of the square roots of the
-- first 8 primes 2..19):
H[1] = 0x6a09e667
H[2] = 0xbb67ae85
H[3] = 0x3c6ef372
H[4] = 0xa54ff53a
H[5] = 0x510e527f
H[6] = 0x9b05688c
H[7] = 0x1f83d9ab
H[8] = 0x5be0cd19
return H
end
local function digestblock (msg, i, H)
-- break chunk into sixteen 32-bit big-endian words w[1..16]
local w = {}
for j = 1, 16 do
w[j] = s232num(msg, i + (j - 1)*4)
end
-- Extend the sixteen 32-bit words into sixty-four 32-bit words:
for j = 17, 64 do
local v = w[j - 15]
local s0 = bxor(rrotate(v, 7), rrotate(v, 18), rshift(v, 3))
v = w[j - 2]
local s1 = bxor(rrotate(v, 17), rrotate(v, 19), rshift(v, 10))
w[j] = w[j - 16] + s0 + w[j - 7] + s1
end
-- Initialize hash value for this chunk:
local a, b, c, d, e, f, g, h =
H[1], H[2], H[3], H[4], H[5], H[6], H[7], H[8]
-- Main loop:
for i = 1, 64 do
local s0 = bxor(rrotate(a, 2), rrotate(a, 13), rrotate(a, 22))
local maj = bxor(band(a, b), band(a, c), band(b, c))
local t2 = s0 + maj
local s1 = bxor(rrotate(e, 6), rrotate(e, 11), rrotate(e, 25))
local ch = bxor (band(e, f), band(bnot(e), g))
local t1 = h + s1 + ch + k[i] + w[i]
h = g
g = f
f = e
e = d + t1
d = c
c = b
b = a
a = t1 + t2
end
-- Add (mod 2^32) this chunk's hash to result so far:
H[1] = band(H[1] + a)
H[2] = band(H[2] + b)
H[3] = band(H[3] + c)
H[4] = band(H[4] + d)
H[5] = band(H[5] + e)
H[6] = band(H[6] + f)
H[7] = band(H[7] + g)
H[8] = band(H[8] + h)
end
local function finalresult224 (H)
-- Produce the final hash value (big-endian):
return
str2hexa(num2s(H[1], 4)..num2s(H[2], 4)..num2s(H[3], 4)..num2s(H[4], 4)..
num2s(H[5], 4)..num2s(H[6], 4)..num2s(H[7], 4))
end
local function finalresult256 (H)
-- Produce the final hash value (big-endian):
return
str2hexa(num2s(H[1], 4)..num2s(H[2], 4)..num2s(H[3], 4)..num2s(H[4], 4)..
num2s(H[5], 4)..num2s(H[6], 4)..num2s(H[7], 4)..num2s(H[8], 4))
end
----------------------------------------------------------------------
local HH = {} -- to reuse
local function hash224 (msg)
msg = preproc(msg, #msg)
local H = initH224(HH)
-- Process the message in successive 512-bit (64 bytes) chunks:
for i = 1, #msg, 64 do
digestblock(msg, i, H)
end
return finalresult224(H)
end
local function hash256 (msg)
msg = preproc(msg, #msg)
local H = initH256(HH)
-- Process the message in successive 512-bit (64 bytes) chunks:
for i = 1, #msg, 64 do
digestblock(msg, i, H)
end
return finalresult256(H)
end
----------------------------------------------------------------------
local mt = {}
local function new256 ()
local o = {H = initH256({}), msg = "", len = 0}
setmetatable(o, mt)
return o
end
mt.__index = mt
function mt:add (m)
self.msg = self.msg .. m
self.len = self.len + #m
local t = 0
while #self.msg - t >= 64 do
digestblock(self.msg, t + 1, self.H)
t = t + 64
end
self.msg = self.msg:sub(t + 1, -1)
end
function mt:close ()
self.msg = preproc(self.msg, self.len)
self:add("")
return finalresult256(self.H)
end
----------------------------------------------------------------------
return {
hash224 = hash224,
hash256 = hash256,
new256 = new256,
}

View File

@@ -29,7 +29,8 @@ local events = {
onMenuEditor = function(self, menu, editor, event) end,
onMenuEditorTab = function(self, menu, notebook, event, index) end,
onMenuFiletree = function(self, menu, tree, event) end,
onProjectLoad = function(self, project) end,
onProjectPreLoad = function(self, project) end, -- before project is changed
onProjectLoad = function(self, project) end, -- after project is changed
onProjectClose = function(self, project) end,
onInterpreterLoad = function(self, interpreter) end,
onInterpreterClose = function(self, interpreter) end,

View File

@@ -1,12 +1,18 @@
-- authors: Luxinia Dev (Eike Decker & Christoph Kubisch)
---------------------------------------------------------
local funccall = "([A-Za-z_][A-Za-z0-9_]*)%s*"
return {
exts = {"cg","cgh","fx","fxh","cgfx","cgfxh",},
exts = {"cg","cgh","cgfx","cgfxh",},
lexer = wxstc.wxSTC_LEX_CPP,
apitype = "cg",
sep = "%.",
linecomment = "//",
isfncall = function(str)
return string.find(str, funccall .. "%(")
end,
isfndef = function(str)
local l

View File

@@ -1,12 +1,18 @@
-- authors: Luxinia Dev (Eike Decker & Christoph Kubisch)
---------------------------------------------------------
local funccall = "([A-Za-z_][A-Za-z0-9_]*)%s*"
return {
exts = {"glsl","vert","frag","geom","cont","eval", "glslv", "glslf"},
lexer = wxstc.wxSTC_LEX_CPP,
apitype = "glsl",
sep = "%.",
linecomment = "//",
isfncall = function(str)
return string.find(str, funccall .. "%(")
end,
isfndef = function(str)
local l
@@ -83,6 +89,7 @@ return {
gl_NumWorkGroups gl_WorkGroupSize gl_WorkGroupID gl_LocalInvocationID gl_GlobalInvocationID gl_LocalInvocationIndex
local_size_x local_size_y local_size_z
gl_BaseVertexARB gl_BaseInstanceARB gl_DrawIDARB
bindless_sampler bound_sampler bindless_image bound_image early_fragment_tests
coherent volatile restrict readonly writeonly
image1D image2D image3D image2DRect imageCube imageBuffer image1DArray image2DArray imageCubeArray image2DMS image2DMSArray
@@ -151,7 +158,7 @@ return {
imageAtomicAdd imageAtomicMin imageAtomicMax
imageAtomicIncWrap imageAtomicDecWrap imageAtomicAnd
imageAtomicOr imageAtomixXor imageAtomicExchange
imageCompSwap
imageAtomicCompSwap imageSize
memoryBarrier groupMemoryBarrier memoryBarrierAtomicCounter memoryBarrierShared memoryBarrierBuffer memoryBarrierImage

View File

@@ -1,12 +1,18 @@
-- authors: Luxinia Dev (Eike Decker & Christoph Kubisch)
---------------------------------------------------------
local funccall = "([A-Za-z_][A-Za-z0-9_]*)%s*"
return {
exts = {"hlsl",},
exts = {"hlsl","fx","fxh",},
lexer = wxstc.wxSTC_LEX_CPP,
apitype = "hlsl",
sep = "%.",
linecomment = "//",
isfncall = function(str)
return string.find(str, funccall .. "%(")
end,
isfndef = function(str)
local l
@@ -47,7 +53,8 @@ return {
half2x3 half2x4 half3x1 half3x2 half3x3 half3x4 half4x1 half4x2 half4x3 half4x4 float1x1 float1x2 float1x3 float1x4 float2x1 float2x2 float2x3
float2x4 float3x1 float3x2 float3x3 float3x4 float4x1 float4x2 float4x3 float4x4 double1x1 double1x2 double1x3 double1x4 double2x1 double2x2
double2x3 double2x4 double3x1 double3x2 double3x3 double3x4 double4x1 double4x2 double4x3 double4x4 cbuffer groupshared SamplerState
in out inout vector matrix interface class point triangle line lineadj triangleadj
in out inout vector matrix interface class point triangle line lineadj triangleadj unsigned
pass technique technique10 technique11
Texture Texture1D Texture1DArray Texture2D Texture2DArray Texture2DMS Texture2DMSArray Texture3D TextureCube RWTexture1D RWTexture1DArray RWTexture2D RWTexture2DArray RWTexture3D
Buffer StructuredBuffer AppendStructuredBuffer ConsumeStructuredBuffer RWBuffer RWStructuredBuffer ByteAddressBuffer RWByteAddressBuffer PointStream TriangleStream LineStream InputPatch OutputPatch

View File

@@ -129,8 +129,8 @@ return {
local tx = editor:GetLine(line) --= string
-- check for assignments
local varname = "([%w_%.]+)"
local identifier = "([%w_%.:%s]+)"
local varname = "([%w_][%w_%.]*)"
local identifier = "([%w_][%w_%.:%s]*)"
-- special hint
local typ,var = tx:match("%s*%-%-=%s*"..varname.."%s+"..identifier)
@@ -160,11 +160,10 @@ return {
end)
-- filter out everything that is not needed
if typ
if typ and typ ~= 'string' -- special value for all strings
and (not typ:match('^'..identifier..'$') -- not an identifier
or typ:match('^%d') -- not an identifier
or typ:match('^%d') -- or a number
or editor.api.tip.keys[typ] -- or a keyword
or editor.api.tip.staticnames[typ] -- or a static name
) then
typ = nil
end

View File

@@ -36,12 +36,18 @@ for i in astypes:gmatch("([%w_]+)") do
end
astypeout = table.concat(astypeout, " ")
local funccall = "([A-Za-z_][A-Za-z0-9_]*)%s*"
return {
exts = {"cl","ocl","clh",},
lexer = wxstc.wxSTC_LEX_CPP,
apitype = "opencl",
sep = "%.",
linecomment = "//",
isfncall = function(str)
return string.find(str, funccall .. "%(")
end,
isfndef = function(str)
local l

View File

@@ -59,7 +59,6 @@ style = {
calltip = stattr,
-- common special (need custom fg & bg )
calltipbg = nil,
sel = nil,
caret = nil,
caretlinebg = nil,
@@ -124,17 +123,17 @@ config = {
runonstart = nil, -- if debugger should run immediately after starting
-- default values are different for different interpreters
redirect = nil, -- "d", "c", or "r" values for default, copy, or redirect
}
},
outputshell = { -- output and shell settings
fontname = "Courier New", -- default font
fontsize = 10, -- defult size
}
},
filetree = { -- filetree settings
fontname = nil, -- no default font as it is system dependent
fontsize = nil, -- no default size as it is system dependent
}
},
keymap = {}, -- mapping of menu IDs to hot keys
messages = {}, -- list of messages in a particular language
@@ -158,7 +157,9 @@ config = {
-- 1: substring leading characters (camel case or _ separated)
-- 2: leading + any correctly ordered fragments (default)
width = 60, -- width of the tooltip text (in characters)
}
},
arg = {}, -- command line arguments
savebak = false, -- if bak files are created on save
@@ -187,7 +188,7 @@ app = {
tools = function(file) return true end,
specs = function(file) return true end,
interpreters = function(file) return true end,
}
},
stringtable = { -- optional entries uses defaults otherwise
editor = nil, statuswelcome = nil,
-- ...
@@ -202,16 +203,16 @@ api = {
-- global space words, e.g "table"
["blah"] = {
-- "function", "class", "keyword", "value", "lib", "method"
-- method is for class:func functions
-- method is for class:func functions
type = "function",
description = "this does something",
-- value/function/method:
-- for autocomplete type guessing, insert the string
-- that the variable name is replace with
-- e.g. "test = somefunc()" somefunc has valuetype of "math"
-- then typing "test." will be treated as "math." in
-- autcomplete logic
-- for autocomplete type guessing, insert the string
-- that the variable name is replace with
-- e.g. "test = somefunc()" somefunc has valuetype of "math"
-- then typing "test." will be treated as "math." in
-- autcomplete logic
valuetype = "api.ClassName",
-- function:
@@ -236,7 +237,7 @@ api = {
-- ----------------------------------------------------
-- all entries are optional
spec = {
exts = {"ext","ext2",..},
exts = {"ext","ext2",},
-- compatible extensions
lexer = wxstc.wxSTC_LEX_LUA,
@@ -247,7 +248,7 @@ spec = {
-- appropriate lexer id
stringeol = {wxstc.wxSTC_LUA_STRINGEOL,},
-- ...
}
},
linecomment = "//",
-- string for linecomments
@@ -258,7 +259,7 @@ spec = {
-- default is "\1" which should yield no matches
-- and therefore disable class.func type autocompletion
isfncall = function(str) return from,to end
isfncall = function(str) return from,to end,
-- function that detects positions for a substring that
-- stands for a functioncall, ie " call(..)" -> 2,5
@@ -320,7 +321,7 @@ debuginterface = {
interpreter = {
name = "",
description = "",
api = {"apifile_without_extension"} -- (opt) to limit loaded lua apis
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)

View File

@@ -107,11 +107,24 @@ end
-- ToolTip and reserved words list
-- also fixes function descriptions
local tipwidth = math.max(20, ide.config.acandtip.width or 60)
local widthmask = ("[^\n]"):rep(tipwidth-10)..("[^\n]?"):rep(10)
local function formatUpToX(s, x)
local splitstr = "([ \t]*)(%S*)([ \t]*)(\n?)"
local t = {""}
for prefix, word, suffix, newline in s:gmatch(splitstr) do
if #(t[#t]) + #prefix + #word > x and #t > 0 then
table.insert(t, word..suffix)
else
t[#t] = t[#t]..prefix..word..suffix
end
if #newline > 0 then table.insert(t, "") end
end
return table.concat(t, "\n")
end
local function fillTips(api,apibasename,apiname)
local apiac = api.ac
local tclass = api.tip
local tipwidth = math.max(20, ide.config.acandtip.width)
tclass.staticnames = {}
tclass.keys = {}
@@ -130,28 +143,20 @@ local function fillTips(api,apibasename,apiname)
local function traverse (tab,libname)
if not tab.childs then return end
for key,info in pairs(tab.childs) do
traverse(info,key)
local fullkey = (libname ~= "" and libname.."." or "")..key
traverse(info, fullkey)
if info.type == "function" or info.type == "method" or info.type == "value" then
local libstr = libname ~= "" and libname.."." or ""
-- fix description
local frontname = (info.returns or "(?)").." "..libstr..key.." "..(info.args or "(?)")
frontname = frontname
:gsub("\n"," ")
:gsub("\t","")
:gsub("("..widthmask..")[ \t]([^%)])","%1\n %2")
info.description = (info.description or "")
:gsub("\n\n","<br>"):gsub("\n"," "):gsub("<br>","\n")
:gsub("[ \t]+"," ")
:gsub("("..widthmask..") ","%1\n")
local frontname = (info.returns or "(?)").." "..fullkey.." "..(info.args or "(?)")
frontname = formatUpToX(frontname:gsub("\n"," "):gsub("\t",""), tipwidth)
local description = formatUpToX(info.description or "", tipwidth)
-- build info
local inf = (info.type == "value" and "" or frontname.."\n")
..info.description
local sentence = info.description:match("^(.-)%. ?\n")
..description
local sentence = description:match("^(.-)%. ?\n")
local infshort = (info.type == "value" and "" or frontname.."\n")
..(sentence and sentence.."..." or info.description)
..(sentence and sentence.."..." or description)
local infshortbatch = (info.returns and info.args) and frontname or infshort
-- add to infoclass

View File

@@ -6,6 +6,7 @@ local frame = ide.frame
local notebook = frame.notebook
local openDocuments = ide.openDocuments
local uimgr = frame.uimgr
local unpack = table.unpack or unpack
local CURRENT_LINE_MARKER = StylesGetMarker("currentline")
local CURRENT_LINE_MARKER_VALUE = 2^CURRENT_LINE_MARKER
@@ -40,20 +41,19 @@ end
function LoadFile(filePath, editor, file_must_exist, skipselection)
local filePath = wx.wxFileName(filePath)
filePath:Normalize() -- make it absolute and remove all .. and . if possible
filePath = filePath:GetFullPath()
-- prevent files from being reopened again
if (not editor) then
for id, doc in pairs(openDocuments) do
if doc.filePath and filePath:SameAs(wx.wxFileName(doc.filePath)) then
if not skipselection and doc.index ~= notebook:GetSelection() then
-- selecting the same tab doesn't trigger PAGE_CHANGE event,
-- but moves the focus to the tab bar, which needs to be avoided.
notebook:SetSelection(doc.index) end
return doc.editor
end
local doc = ide:FindDocument(filePath)
if doc then
if not skipselection and doc.index ~= notebook:GetSelection() then
-- selecting the same tab doesn't trigger PAGE_CHANGE event,
-- but moves the focus to the tab bar, which needs to be avoided.
notebook:SetSelection(doc.index) end
return doc.editor
end
end
filePath = filePath:GetFullPath()
-- if not opened yet, try open now
local file_text = FileRead(filePath)
@@ -71,6 +71,16 @@ function LoadFile(filePath, editor, file_must_exist, skipselection)
editor:Freeze()
SetupKeywords(editor, GetFileExt(filePath))
editor:MarkerDeleteAll(-1)
-- remove BOM from UTF-8 encoded files; store BOM to add back when saving
editor.bom = string.char(0xEF,0xBB,0xBF)
if file_text and editor:GetCodePage() == wxstc.wxSTC_CP_UTF8
and file_text:find("^"..editor.bom) then
file_text = file_text:gsub("^"..editor.bom, "")
else
-- set to 'false' as checks for nil on wxlua objects may fail at run-time
editor.bom = false
end
editor:SetText(file_text or "")
-- check the editor as it can be empty if the file has malformed UTF8;
@@ -133,14 +143,53 @@ function LoadFile(filePath, editor, file_must_exist, skipselection)
openDocuments[id].fileName = wx.wxFileName(filePath):GetFullName()
openDocuments[id].modTime = GetFileModTime(filePath)
PackageEventHandle("onEditorLoad", editor)
SetDocumentModified(id, false)
SetDocumentModified(id, false, openDocuments[id].fileName)
-- activate the editor; this is needed for those cases when the editor is
-- created from some other element, for example, from a project tree.
if not skipselection then SetEditorSelection() end
PackageEventHandle("onEditorLoad", editor)
return editor
end
function ReLoadFile(filePath, editor, ...)
if not editor then return LoadFile(filePath, editor, ...) end
-- save all markers
local maskany = 2^24-1
local markers = {}
local line = editor:MarkerNext(0, maskany)
while line > -1 do
table.insert(markers, {line, editor:MarkerGet(line), editor:GetLine(line)})
line = editor:MarkerNext(line + 1, maskany)
end
local lines = editor:GetLineCount()
-- load file into the same editor
editor = LoadFile(filePath, editor, ...)
if not editor then return end
if #markers > 0 then -- restore all markers
local samelinecount = lines == editor:GetLineCount()
for _, marker in ipairs(markers) do
local line, mask, text = unpack(marker)
if samelinecount then
-- restore marker at the same line number
editor:MarkerAddSet(line, mask)
else
-- find matching line in the surrounding area and restore marker there
for _, l in ipairs({line, line-1, line-2, line+1, line+2}) do
if text == editor:GetLine(l) then
editor:MarkerAddSet(l, mask)
break
end
end
end
end
end
return editor
end
@@ -159,6 +208,10 @@ local function getExtsString()
return exts..TR("All files").." (*)|*"
end
function ReportError(msg)
return wx.wxMessageBox(msg, TR("Error"), wx.wxICON_ERROR + wx.wxOK + wx.wxCENTRE, ide.frame)
end
function OpenFile(event)
local exts = getExtsString()
local fileDialog = wx.wxFileDialog(ide.frame, TR("Open file"),
@@ -168,9 +221,7 @@ function OpenFile(event)
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(TR("Unable to load file '%s'."):format(fileDialog:GetPath()),
TR("Error"),
wx.wxOK + wx.wxCENTRE, ide.frame)
ReportError(TR("Unable to load file '%s'."):format(fileDialog:GetPath()))
end
end
fileDialog:Destroy()
@@ -178,26 +229,30 @@ end
-- save the file to filePath or if filePath is nil then call SaveFileAs
function SaveFile(editor, filePath)
-- this event can be aborted
-- as SaveFileAs calls SaveFile, this event may be called two times:
-- first without filePath and then with filePath
if PackageEventHandle("onEditorPreSave", editor, filePath) == false then
return false
end
if not filePath then
return SaveFileAs(editor)
else
-- this event can be aborted
if PackageEventHandle("onEditorPreSave", editor, filePath) == false then
return false
if ide.config.savebak then
local ok, err = FileRename(filePath, filePath..".bak")
if not ok then
ReportError(TR("Unable to save file '%s': %s"):format(filePath..".bak", err))
return
end
end
if (ide.config.savebak) then FileRename(filePath, filePath..".bak") end
local st = editor:GetText()
local st = (editor:GetCodePage() == wxstc.wxSTC_CP_UTF8 and editor.bom or "")
.. editor:GetText()
if GetConfigIOFilter("output") then
st = GetConfigIOFilter("output")(filePath,st)
end
local file = wx.wxFileName(filePath)
if not file:FileExists() then
file:Mkdir(tonumber(755,8), wx.wxPATH_MKDIR_FULL)
end
local ok, err = FileWrite(filePath, st)
if ok then
editor:SetSavePoint()
@@ -205,22 +260,27 @@ function SaveFile(editor, filePath)
openDocuments[id].filePath = filePath
openDocuments[id].fileName = wx.wxFileName(filePath):GetFullName()
openDocuments[id].modTime = GetFileModTime(filePath)
SetDocumentModified(id, false)
SetDocumentModified(id, false, openDocuments[id].fileName)
SetAutoRecoveryMark()
PackageEventHandle("onEditorSave", editor)
return true
else
wx.wxMessageBox(TR("Unable to save file '%s': %s"):format(filePath, err),
TR("Error"),
wx.wxICON_ERROR + wx.wxOK + wx.wxCENTRE, ide.frame)
ReportError(TR("Unable to save file '%s': %s"):format(filePath, err))
end
end
return false
end
function ApproveFileOverwrite()
return wx.wxMessageBox(
TR("File already exists.").."\n"..TR("Do you want to overwrite it?"),
GetIDEString("editormessage"),
wx.wxYES_NO + wx.wxCENTRE, ide.frame) == wx.wxYES
end
function SaveFileAs(editor)
local id = editor:GetId()
local saved = false
@@ -248,17 +308,13 @@ function SaveFileAs(editor)
if fileDialog:ShowModal() == wx.wxID_OK then
local filePath = fileDialog:GetPath()
-- first check if there is another tab with the same name and close it
local existing
local fileName = wx.wxFileName(filePath)
for _, document in pairs(ide.openDocuments) do
if document.filePath and fileName:SameAs(wx.wxFileName(document.filePath)) then
existing = document.index
break
end
end
-- check if there is another tab with the same name and prepare to close it
local existing = (ide:FindDocument(filePath) or {}).index
local cansave = fn:GetFullName() == filePath -- saving into the same file
or not wx.wxFileName(filePath):FileExists() -- or a new file
or ApproveFileOverwrite()
if SaveFile(editor, filePath) then
if cansave and SaveFile(editor, filePath) then
SetEditorSelection() -- update title of the editor
FileTreeMarkSelected(filePath)
if ext ~= GetFileExt(filePath) then
@@ -440,8 +496,8 @@ function FoldSome()
for ln = 0, editor.LineCount - 1 do
local foldRaw = editor:GetFoldLevel(ln)
local foldLvl = math.mod(foldRaw, 4096)
local foldHdr = math.mod(math.floor(foldRaw / 8192), 2) == 1
local foldLvl = foldRaw % 4096
local foldHdr = (math.floor(foldRaw / 8192) % 2) == 1
-- at least one header is expanded
foldall = foldall or (foldHdr and editor:GetFoldExpanded(ln))
@@ -460,8 +516,8 @@ function FoldSome()
for ln = 0, editor.LineCount-1 do
local foldRaw = editor:GetFoldLevel(ln)
local foldLvl = math.mod(foldRaw, 4096)
local foldHdr = math.mod(math.floor(foldRaw / 8192), 2) == 1
local foldLvl = foldRaw % 4096
local foldHdr = (math.floor(foldRaw / 8192) % 2) == 1
if foldall then
if foldHdr and editor:GetFoldExpanded(ln) then
@@ -507,36 +563,51 @@ function ClearAllCurrentLineMarkers()
end
end
-- 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.
function StripShebang(code) return (code:gsub("^#!.-\n", "\n")) end
local compileOk, compileTotal = 0, 0
function CompileProgram(editor, quiet)
-- 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")
function CompileProgram(editor, params)
local params = { jumponerror = (params or {}).jumponerror ~= false,
reportstats = (params or {}).reportstats ~= false }
local id = editor:GetId()
local filePath = DebuggerMakeFileName(editor, openDocuments[id].filePath)
local func, line_num, errMsg, _ = loadstring(editorText, filePath), -1
if not func then
_, errMsg, line_num = wxlua.CompileLuaScript(editorText, filePath)
end
local func, err = loadstring(StripShebang(editor:GetText()), '@'..filePath)
local line = not func and tonumber(err:match(":(%d+)%s*:")) or nil
if ide.frame.menuBar:IsChecked(ID_CLEAROUTPUT) then ClearOutput() end
compileTotal = compileTotal + 1
if line_num > -1 then
DisplayOutput(TR("Compilation error")
.." "..TR("on line %d"):format(line_num)
..":\n"..errMsg:gsub("Lua:.-\n", ""))
if not quiet then editor:GotoLine(line_num-1) end
else
if func then
compileOk = compileOk + 1
if not quiet then
if params.reportstats then
DisplayOutputLn(TR("Compilation successful; %.0f%% success rate (%d/%d).")
:format(compileOk/compileTotal*100, compileOk, compileTotal))
end
else
DisplayOutputLn(TR("Compilation error").." "..TR("on line %d"):format(line)..":")
DisplayOutputLn((err:gsub("\n$", "")))
-- check for escapes invalid in LuaJIT/Lua 5.2 that are allowed in Lua 5.1
if err:find('invalid escape sequence') then
local s = editor:GetLine(line-1)
local cleaned = s
:gsub('\\[abfnrtv\\"\']', ' ')
:gsub('(\\x[0-9a-fA-F][0-9a-fA-F])', function(s) return string.rep(' ', #s) end)
:gsub('(\\%d%d?%d?)', function(s) return string.rep(' ', #s) end)
:gsub('(\\z%s*)', function(s) return string.rep(' ', #s) end)
local invalid = cleaned:find("\\")
if invalid then
DisplayOutputLn(TR("Consider removing backslash from escape sequence '%s'.")
:format(s:sub(invalid,invalid+1)))
end
end
if line and params.jumponerror and line-1 ~= editor:GetCurrentLine() then
editor:GotoLine(line-1) end
end
return line_num == -1, editorText -- return true if it compiled ok
return func ~= nil -- return true if it compiled ok
end
------------------
@@ -637,8 +708,7 @@ function ProjectConfig(dir, config)
end
function SetOpenTabs(params)
local recovery, nametab = loadstring("return "..params.recovery)
if recovery then recovery, nametab = pcall(recovery) end
local recovery, nametab = LoadSafe("return "..params.recovery)
if not recovery then
DisplayOutputLn(TR("Can't process auto-recovery record; invalid format: %s."):format(nametab))
return
@@ -685,10 +755,12 @@ function SetAutoRecoveryMark()
end
local function saveAutoRecovery(event)
if not ide.config.autorecoverinactivity or not ide.session.lastupdated then return end
if ide.session.lastupdated < (ide.session.lastsaved or 0)
or ide.session.lastupdated + ide.config.autorecoverinactivity > os.time()
then return end
local lastupdated = ide.session.lastupdated
if not ide.config.autorecoverinactivity or not lastupdated then return end
if lastupdated < (ide.session.lastsaved or 0) then return end
local now = os.time()
if lastupdated + ide.config.autorecoverinactivity > now then return end
-- find all open modified files and save them
local opentabs, params = getOpenTabs()
@@ -698,7 +770,7 @@ local function saveAutoRecovery(event)
SettingsSaveFileSession({}, params)
ide.settings:Flush()
end
ide.session.lastsaved = os.time()
ide.session.lastsaved = now
ide.frame.statusBar:SetStatusText(
TR("Saved auto-recover at %s."):format(os.date("%H:%M:%S")), 1)
end
@@ -757,7 +829,7 @@ function StoreRestoreProjectTabs(curdir, newdir)
fastWrap(SetOpenFiles, files, {index = #files + notebook:GetPageCount()})
end
if params and params.interpreter and ide.interpreter.fname ~= params.interpreter then
if params and params.interpreter then
ProjectSetInterpreter(params.interpreter) -- set the interpreter
end
@@ -829,6 +901,17 @@ frame:Connect(wx.wxEVT_TIMER, saveAutoRecovery)
ide.editorApp:Connect(wx.wxEVT_ACTIVATE_APP,
function(event)
if not ide.exitingProgram then
-- wxSTC controls on OSX don't generate KILL_FOCUS events
-- when focus is switched between controls in the app;
-- manually kill focus when the app is deactivated
if ide.osname == 'Macintosh' and not event:GetActive() then
local ntbk = frame.bottomnotebook
for _,win in ipairs({ntbk.errorlog, ntbk.shellbox, GetEditor()}) do
local ev = wx.wxFocusEvent(wx.wxEVT_KILL_FOCUS)
win:GetEventHandler():ProcessEvent(ev)
end
end
local event = event:GetActive() and "onAppFocusSet" or "onAppFocusLost"
PackageEventHandle(event, ide.editorApp)
end

View File

@@ -6,6 +6,7 @@
local copas = require "copas"
local socket = require "socket"
local mobdebug = require "mobdebug"
local unpack = table.unpack or unpack
local ide = ide
local debugger = ide.debugger
@@ -37,18 +38,23 @@ local stackmaxnum = ide.config.debugger.stackmaxnum or 400
local stackmaxlevel = ide.config.debugger.stackmaxlevel or 3
local params = {comment = false, nocode = true, maxlevel = stackmaxlevel, maxnum = stackmaxnum}
function fixUTF8(...)
local function fixUTF8(...)
local t = {...}
-- convert to escaped decimal code as these can only appear in strings
local function fix(s) return '\\'..string.byte(s) end
for i = 1, #t do
local text = t[i]:sub(1, stackmaxlength)..(#t[i] > stackmaxlength and '...' or '')
t[i] = FixUTF8(text, fix)
end
return (table.unpack or unpack)(t)
for i = 1, #t do t[i] = FixUTF8(t[i], fix) end
return unpack(t)
end
local function q(s) return s:gsub('([%(%)%.%%%+%-%*%?%[%^%$%]])','%%%1') end
local function trimToMaxLength(...)
local t = {...}
for i = 1, #t do
t[i] = t[i]:sub(1, stackmaxlength)..(#t[i] > stackmaxlength and '...' or '')
end
return unpack(t)
end
local q = EscapeMagic
local function updateWatchesSync(num)
local watchCtrl = debugger.watchCtrl
@@ -150,9 +156,9 @@ local function updateStackSync()
-- comment can be not necessarily a string for tables with metatables
-- that provide its own __tostring method
local value, comment = val[1], fixUTF8(tostring(val[2]))
local value, comment = val[1], fixUTF8(trimToMaxLength(tostring(val[2])))
local text = ("%s = %s%s"):
format(name, fixUTF8(serialize(value, params)),
format(name, fixUTF8(trimToMaxLength(serialize(value, params))),
simpleType[type(value)] and "" or (" --[["..comment.."]]"))
local item = stackCtrl:AppendItem(callitem, text, 1)
if checkIfExpandable(value, item) then
@@ -162,9 +168,9 @@ local function updateStackSync()
-- add the upvalues for this call stack level to the tree item
for name,val in pairs(frame[3]) do
local value, comment = val[1], fixUTF8(tostring(val[2]))
local value, comment = val[1], fixUTF8(trimToMaxLength(tostring(val[2])))
local text = ("%s = %s%s"):
format(name, fixUTF8(serialize(value, params)),
format(name, fixUTF8(trimToMaxLength(serialize(value, params))),
simpleType[type(value)] and "" or (" --[["..comment.."]]"))
local item = stackCtrl:AppendItem(callitem, text, 2)
if checkIfExpandable(value, item) then
@@ -416,7 +422,7 @@ debugger.shell = function(expression, isstatement)
if #values == 0 and (forceexpression or not isstatement) then
values = {'nil'}
end
DisplayShell(fixUTF8((table.unpack or unpack)(values)))
DisplayShell(fixUTF8(unpack(values)))
end
-- refresh Stack and Watch windows if executed a statement (and no err)
@@ -437,7 +443,12 @@ local function stoppedAtBreakpoint(file, line)
end
debugger.listen = function()
local server = socket.bind("*", debugger.portnumber)
local server, err = socket.bind("*", debugger.portnumber)
if not server then
DisplayOutputLn(TR("Can't start debugger server at %s:%d: %s.")
:format(debugger.hostname, debugger.portnumber, err or TR("unknown error")))
return
end
DisplayOutputLn(TR("Debugger server started at %s:%d.")
:format(debugger.hostname, debugger.portnumber))
copas.autoclose = false
@@ -503,10 +514,9 @@ debugger.listen = function()
-- if it's an error returned, then handle the error
if m and m:find("stack traceback:", 1, true) then
-- this is an error message sent remotely
local func = loadstring("return "..m)
if func then
DisplayOutputLn(func())
debugger.terminate()
local ok, res = LoadSafe("return "..m)
if ok then
DisplayOutputLn(res)
return
end
end
@@ -747,15 +757,23 @@ end
do
local nextupdatedelta = 0.250
local nextupdate = TimeGet() + nextupdatedelta
local function forceUpdateOnWrap(editor)
-- http://www.scintilla.org/ScintillaDoc.html#LineWrapping
-- Scintilla doesn't perform wrapping immediately after a content change
-- for performance reasons, so the activation calculations can be wrong
-- if there is wrapping that pushes the current line out of the screen.
-- force editor update that performs wrapping recalculation.
if ide.config.editor.usewrap then editor:Update(); editor:Refresh() end
end
debugger.update = function()
if debugger.server or debugger.listening and TimeGet() > nextupdate then
copas.step(0)
nextupdate = TimeGet() + nextupdatedelta
end
-- if there are any pending activations
-- if there is any pending activation
if debugger.activate then
local file, line, content = (table.unpack or unpack)(debugger.activate)
local file, line, content = unpack(debugger.activate)
if content then
local editor = NewFile()
editor:SetText(content)
@@ -763,9 +781,14 @@ do
and not (debugger.options or {}).allowediting then
editor:SetReadOnly(true)
end
forceUpdateOnWrap(editor)
activateDocument(file, line)
elseif LoadFile(file) then
activateDocument(file, line)
else
local editor = LoadFile(file)
if editor then
forceUpdateOnWrap(editor)
activateDocument(file, line)
end
end
debugger.activate = nil
end
@@ -852,7 +875,7 @@ function debuggerAddWindow(ctrl, panel, name)
wx.wxDefaultPosition, wx.wxDefaultSize,
wxaui.wxAUI_NB_DEFAULT_STYLE + wxaui.wxAUI_NB_TAB_EXTERNAL_MOVE
- wxaui.wxAUI_NB_CLOSE_ON_ACTIVE_TAB + wx.wxNO_BORDER)
notebook:AddPage(ctrl, TR(name), true)
notebook:AddPage(ctrl, name, true)
local mgr = ide.frame.uimgr
mgr:AddPane(notebook, wxaui.wxAuiPaneInfo():
@@ -866,11 +889,11 @@ function debuggerAddWindow(ctrl, panel, name)
end
function DebuggerAddStackWindow()
return debuggerAddWindow(debugger.stackCtrl, "stackpanel", "Stack")
return debuggerAddWindow(debugger.stackCtrl, "stackpanel", TR("Stack"))
end
function DebuggerAddWatchWindow()
return debuggerAddWindow(debugger.watchCtrl, "watchpanel", "Watch")
return debuggerAddWindow(debugger.watchCtrl, "watchpanel", TR("Watch"))
end
function debuggerCreateStackWindow()
@@ -891,7 +914,7 @@ function debuggerCreateStackWindow()
local image = stackCtrl:GetItemImage(item_id)
local num = 1
for name,value in pairs(stackItemValue[item_id:GetValue()]) do
local strval = fixUTF8(serialize(value, params))
local strval = fixUTF8(trimToMaxLength(serialize(value, params)))
local text = type(name) == "number"
and (num == name and strval or ("[%s] = %s"):format(name, strval))
or ("%s = %s"):format(tostring(name), strval)
@@ -948,10 +971,11 @@ local function debuggerCreateWatchWindow()
info:SetWidth(width * 0.56)
watchCtrl:InsertColumn(1, info)
local watchMenu = wx.wxMenu{
local watchMenu = wx.wxMenu {
{ ID_ADDWATCH, TR("&Add Watch")..KSC(ID_ADDWATCH) },
{ ID_EDITWATCH, TR("&Edit Watch")..KSC(ID_EDITWATCH) },
{ ID_DELETEWATCH, TR("&Delete Watch")..KSC(ID_DELETEWATCH) }}
{ ID_DELETEWATCH, TR("&Delete Watch")..KSC(ID_DELETEWATCH) },
}
local function findSelectedWatchItem()
local count = watchCtrl:GetSelectedItemCount()
@@ -1098,22 +1122,15 @@ function DebuggerToggleBreakpoint(editor, line)
-- ignore requests to toggle when the debugger is running
if debugger.server and debugger.running then return end
local markers = editor:MarkerGet(line)
if markers >= CURRENT_LINE_MARKER_VALUE then
markers = markers - CURRENT_LINE_MARKER_VALUE
end
local id = editor:GetId()
local filePath = debugger.editormap and debugger.editormap[editor]
or DebuggerMakeFileName(editor, ide.openDocuments[id].filePath)
if markers >= BREAKPOINT_MARKER_VALUE then
if bit.band(markers, BREAKPOINT_MARKER_VALUE) > 0 then
editor:MarkerDelete(line, BREAKPOINT_MARKER)
if debugger.server then
debugger.breakpoint(filePath, line+1, false)
end
if debugger.server then debugger.breakpoint(filePath, line+1, false) end
else
editor:MarkerAdd(line, BREAKPOINT_MARKER)
if debugger.server then
debugger.breakpoint(filePath, line+1, true)
end
if debugger.server then debugger.breakpoint(filePath, line+1, true) end
end
end
@@ -1123,9 +1140,13 @@ function DebuggerRefreshScratchpad()
if debugger.scratchpad and debugger.scratchpad.updated and not debugger.scratchpad.paused then
local scratchpadEditor = debugger.scratchpad.editor
local compiled, code = CompileProgram(scratchpadEditor, true)
if not compiled then return end
if scratchpadEditor.spec.apitype
and scratchpadEditor.spec.apitype == "lua"
and not ide.interpreter.skipcompile
and not CompileProgram(scratchpadEditor, { jumponerror = false, reportstats = false })
then return end
local code = StripShebang(scratchpadEditor:GetText())
if debugger.scratchpad.running then
-- break the current execution first
-- don't try too frequently to avoid overwhelming the debugger

View File

@@ -12,6 +12,7 @@ local notebook = ide.frame.notebook
local funclist = ide.frame.toolBar.funclist
local edcfg = ide.config.editor
local styles = ide.config.styles
local unpack = table.unpack or unpack
local DEFAULT_STYLE = 32
local margin = { LINENUMBER = 0, MARKER = 1, FOLD = 2 }
@@ -29,15 +30,21 @@ local function updateStatusText(editor)
local pos = editor:GetCurrentPos()
local line = editor:LineFromPosition(pos)
local col = 1 + pos - editor:PositionFromLine(line)
local selected = #editor:GetSelectedText()
local selections = ide.wxver >= "2.9.5" and editor:GetSelections() or 1
texts = {
iff(editor:GetOvertype(), TR("OVR"), TR("INS")),
iff(editor:GetReadOnly(), TR("R/O"), TR("R/W")),
TR("Ln: %d"):format(line + 1).." "..TR("Col: %d"):format(col) }
table.concat({
TR("Ln: %d"):format(line + 1),
TR("Col: %d"):format(col),
selected > 0 and TR("Sel: %d/%d"):format(selected, selections) or "",
}, ' ')}
end
if ide.frame then
for n = 1, 3 do
for n in ipairs(texts) do
if (texts[n] ~= statusTextTable[n]) then
statusBar:SetStatusText(texts[n], n+1)
statusTextTable[n] = texts[n]
@@ -118,7 +125,7 @@ local function isFileAlteredOnDisk(editor)
GetIDEString("editormessage"),
wx.wxYES_NO + wx.wxCENTRE, ide.frame)
if ret ~= wx.wxYES or LoadFile(filePath, editor, true) then
if ret ~= wx.wxYES or ReLoadFile(filePath, editor, true) then
openDocuments[id].modTime = GetFileModTime(filePath)
end
end
@@ -138,6 +145,7 @@ local function navigateBack(editor)
if #editor.jumpstack == 0 then return end
local pos = table.remove(editor.jumpstack)
editor:GotoPos(pos)
return true
end
-- ----------------------------------------------------------------------------
@@ -202,16 +210,14 @@ function GetEditorFileAndCurInfo(nochecksave)
end
-- Set if the document is modified and update the notebook page text
function SetDocumentModified(id, modified)
if not openDocuments[id] then return end
local pageText = openDocuments[id].fileName or ide.config.default.fullname
if modified then
pageText = "* "..pageText
end
function SetDocumentModified(id, modified, text)
local modpref, doc = '* ', openDocuments[id]
if not doc then return end
local pageText = text or notebook:GetPageText(doc.index):gsub("^"..EscapeMagic(modpref), "")
if modified then pageText = modpref..pageText end
openDocuments[id].isModified = modified
notebook:SetPageText(openDocuments[id].index, pageText)
notebook:SetPageText(doc.index, pageText)
end
function EditorAutoComplete(editor)
@@ -308,6 +314,38 @@ local function getValAtPosition(editor, pos)
return var, funccall
end
local function callTipFitAndShow(editor, pos, tip)
local point = editor:PointFromPosition(pos)
local height = editor:TextHeight(pos)
local maxlines = math.max(1, math.floor(
math.max(editor:GetSize():GetHeight()-point:GetY()-height, point:GetY())/height-1
))
-- cut the tip to not exceed the number of maxlines.
-- move the position to the left if needed to fit.
-- find the longest line in terms of width in pixels.
local maxwidth = 0
local lines = {}
for line in tip:gmatch("[^\n]*\n?") do
local width = editor:TextWidth(wxstc.wxSTC_STYLE_DEFAULT, line)
if width > maxwidth then maxwidth = width end
table.insert(lines, line)
if #lines >= maxlines then
lines[#lines] = lines[#lines]:gsub("%s*\n$","")..'...'
break
end
end
tip = table.concat(lines, '')
local startpos = editor:PositionFromLine(editor:LineFromPosition(pos))
local afterwidth = editor:GetSize():GetWidth()-point:GetX()
if maxwidth > afterwidth then
local charwidth = editor:TextWidth(wxstc.wxSTC_STYLE_DEFAULT, 'A')
pos = math.max(startpos, pos - math.floor((maxwidth - afterwidth) / charwidth))
end
editor:CallTipShow(pos, tip)
end
function EditorCallTip(editor, pos, x, y)
-- don't show anything if the calltip/auto-complete is active;
-- this may happen after typing function name, while the mouse is over
@@ -332,7 +370,8 @@ function EditorCallTip(editor, pos, x, y)
local mpos = wx.wxGetMousePosition()
if mpos.x ~= x or mpos.y ~= y then return end
end
editor:CallTipShow(pos, val) end)
callTipFitAndShow(editor, pos, val)
end)
end
elseif tip then
-- only shorten if shown on mouse-over. Use shortcut to get full info.
@@ -343,7 +382,7 @@ function EditorCallTip(editor, pos, x, y)
if x and y and #tip > shortento then
tip = tip:sub(1, shortento-#suffix):gsub("%W*%w*$","")..suffix
end
editor:CallTipShow(pos, tip)
callTipFitAndShow(editor, pos, tip)
end
end
@@ -358,7 +397,7 @@ function EditorIsModified(editor)
end
-- Indicator handling for functions and local/global variables
local function indicateFunctions28(editor, lines, linee)
local function indicateFunctionsOnly(editor, lines, linee)
if not (edcfg.showfncall and editor.spec and editor.spec.isfncall)
or not (styles.indicator and styles.indicator.fncall) then return end
@@ -458,9 +497,12 @@ function IndicateAll(editor, lines, linee)
-- this function can be called for an editor tab that is already closed
-- when there are still some pending events for it, so handle it.
if not pcall(function() return editor:GetId() end) then return end
if not pcall(function() editor:GetId() end) then return end
if not (editor.spec and editor.spec.markvars) then return end
-- if markvars is not set in the spec, check for functions-only indicators
if not (editor.spec and editor.spec.markvars) then
return indicateFunctionsOnly(editor, lines, linee)
end
local indic = styles.indicator or {}
local pos, vars = d and d[1] or 1, d and d[2] or nil
@@ -583,7 +625,7 @@ function IndicateAll(editor, lines, linee)
end
if ide.wxver < "2.9.5" or not ide.config.autoanalizer then
IndicateAll = indicateFunctions28 end
IndicateAll = indicateFunctionsOnly end
-- ----------------------------------------------------------------------------
-- Create an editor
@@ -597,7 +639,27 @@ function CreateEditor()
editor.matchon = false
editor.assignscache = false
editor.autocomplete = false
editor.bom = false
editor.jumpstack = {}
editor.ctrlcache = {}
-- populate cache with Ctrl-<letter> combinations for workaround on Linux
-- http://wxwidgets.10942.n7.nabble.com/Menu-shortcuts-inconsistentcy-issue-td85065.html
for id, shortcut in pairs(ide.config.keymap) do
local key = shortcut:match('^Ctrl[-+](%w)$')
if key then editor.ctrlcache[key:byte()] = id end
end
-- populate editor keymap with configured combinations
for _, map in ipairs(ide.config.editor.keymap) do
local key, mod, cmd, os = unpack(map)
if not os or os == ide.osname then
if cmd then
editor:CmdKeyAssign(key, mod, cmd)
else
editor:CmdKeyClear(key, mod)
end
end
end
editor:SetBufferedDraw(not ide.config.hidpi and true or false)
editor:StyleClearAll()
@@ -806,7 +868,7 @@ function CreateEditor()
local tip = GetTipInfo(editor,linetxtopos,ide.config.acandtip.shorttip)
if tip then
if editor:CallTipActive() then editor:CallTipCancel() end
editor:CallTipShow(pos,tip)
callTipFitAndShow(editor, pos, tip)
end
elseif ide.config.autocomplete then -- code completion prompt
@@ -913,7 +975,17 @@ function CreateEditor()
editor:Connect(wxstc.wxEVT_STC_PAINTED,
function ()
if ide.osname == 'Windows' then updateStatusText(editor) end
if ide.osname == 'Windows' then
updateStatusText(editor)
if ide.config.editor.usewrap ~= true and editor:AutoCompActive() then
-- showing auto-complete list leaves artifacts on the screen,
-- which can only be fixed by a forced refresh.
-- shows with wxSTC 3.21 and both wxwidgets 2.9.5 and 3.1
editor:Update()
editor:Refresh()
end
end
end)
editor:Connect(wxstc.wxEVT_STC_UPDATEUI,
@@ -1044,12 +1116,14 @@ function CreateEditor()
editor:SetTargetEnd(pos+1)
end
editor:ReplaceTarget("")
elseif ide.osname == "Unix" and ide.wxver >= "2.9.5"
and keycode == ('T'):byte() and mod == wx.wxMOD_CONTROL then
ide.frame:AddPendingEvent(wx.wxCommandEvent(
wx.wxEVT_COMMAND_MENU_SELECTED, ID_SHOWTOOLTIP))
elseif mod == wx.wxMOD_ALT and keycode == wx.WXK_LEFT then
navigateBack(editor)
-- if no "jump back" is needed, then do normal processing as this
-- combination can be mapped to some action
if not navigateBack(editor) then event:Skip() end
elseif ide.osname == "Unix" and ide.wxver >= "2.9.5"
and mod == wx.wxMOD_CONTROL and editor.ctrlcache[keycode] then
ide.frame:AddPendingEvent(wx.wxCommandEvent(
wx.wxEVT_COMMAND_MENU_SELECTED, editor.ctrlcache[keycode]))
else
if ide.osname == 'Macintosh' and mod == wx.wxMOD_META then
return -- ignore a key press if Command key is also pressed
@@ -1098,6 +1172,14 @@ function CreateEditor()
editor:Connect(wxstc.wxEVT_STC_ZOOM,
function(event)
editor:SetMarginWidth(margin.LINENUMBER, editor:TextWidth(DEFAULT_STYLE, "99999_"))
-- if Shift+Zoom is used, then zoom all editors, not just the current one
if wx.wxGetKeyState(wx.WXK_SHIFT) then
local zoom = editor:GetZoom()
for id, doc in pairs(openDocuments) do
-- check the editor zoom level to avoid recursion
if doc.editor:GetZoom() ~= zoom then doc.editor:SetZoom(zoom) end
end
end
event:Skip()
end)
@@ -1114,21 +1196,22 @@ function CreateEditor()
local line = instances and instances[0] and editor:LineFromPosition(instances[0]-1)+1
local def = line and " ("..TR("on line %d"):format(line)..")" or ""
local menu = wx.wxMenu()
menu:Append(ID_UNDO, TR("&Undo"))
menu:Append(ID_REDO, TR("&Redo"))
menu:AppendSeparator()
menu:Append(ID_CUT, TR("Cu&t"))
menu:Append(ID_COPY, TR("&Copy"))
menu:Append(ID_PASTE, TR("&Paste"))
menu:Append(ID_SELECTALL, TR("Select &All"))
menu:AppendSeparator()
menu:Append(ID_GOTODEFINITION, TR("Go To Definition")..def)
menu:Append(ID_RENAMEALLINSTANCES, TR("Rename All Instances")..occurrences)
menu:AppendSeparator()
menu:Append(ID_QUICKADDWATCH, TR("Add Watch Expression"))
menu:Append(ID_QUICKEVAL, TR("Evaluate In Console"))
menu:Append(ID_ADDTOSCRATCHPAD, TR("Add To Scratchpad"))
local menu = wx.wxMenu {
{ ID_UNDO, TR("&Undo") },
{ ID_REDO, TR("&Redo") },
{ },
{ ID_CUT, TR("Cu&t") },
{ ID_COPY, TR("&Copy") },
{ ID_PASTE, TR("&Paste") },
{ ID_SELECTALL, TR("Select &All") },
{ },
{ ID_GOTODEFINITION, TR("Go To Definition")..def },
{ ID_RENAMEALLINSTANCES, TR("Rename All Instances")..occurrences },
{ },
{ ID_QUICKADDWATCH, TR("Add Watch Expression") },
{ ID_QUICKEVAL, TR("Evaluate In Console") },
{ ID_ADDTOSCRATCHPAD, TR("Add To Scratchpad") },
}
menu:Enable(ID_GOTODEFINITION, instances and instances[0])
menu:Enable(ID_RENAMEALLINSTANCES, instances and (instances[0] or #instances > 0))

View File

@@ -15,6 +15,7 @@ local filetree = ide.filetree
local iscaseinsensitive = wx.wxFileName("A"):SameAs(wx.wxFileName("a"))
local pathsep = GetPathSeparator()
local q = EscapeMagic
-- generic tree
-- ------------
@@ -94,6 +95,44 @@ local function treeSetRoot(tree,rootdir)
tree:Expand(root_id) -- this will also populate the tree
end
local function findItem(tree, match)
local node = tree:GetRootItem()
local label = tree:GetItemText(node)
local s, e
if iscaseinsensitive then
s, e = string.find(match:lower(), label:lower(), 1, true)
else
s, e = string.find(match, label, 1, true)
end
if not s or s ~= 1 then return end
for token in string.gmatch(string.sub(match,e+1), "[^%"..pathsep.."]+") do
local data = tree:GetItemData(node)
local cache = data and data:GetData()
if cache and cache[iscaseinsensitive and token:lower() or token] then
node = cache[iscaseinsensitive and token:lower() or token]
else
-- token is missing; may need to re-scan the folder; maybe new file
local dir = tree:GetItemFullName(node)
treeAddDir(tree,node,dir)
local item, cookie = tree:GetFirstChild(node)
while true do
if not item:IsOk() then return end -- not found
if tree:GetItemText(item) == token then
node = item
break
end
item, cookie = tree:GetNextChild(node, cookie)
end
end
end
-- this loop exits only when a match is found
return node
end
local function treeSetConnectorsAndIcons(tree)
tree:SetImageList(filetree.imglist)
@@ -115,24 +154,113 @@ local function treeSetConnectorsAndIcons(tree)
end
local function refreshAncestors(node)
-- when this method is called from END_EDIT, it causes infinite loop
-- on OSX (wxwidgets 2.9.5) as Delete in treeAddDir calls END_EDIT again.
-- disable handlers while the tree is populated and then enable back.
tree:SetEvtHandlerEnabled(false)
while node:IsOk() do
local dir = tree:GetItemFullName(node)
treeAddDir(tree,node,dir)
node = tree:GetItemParent(node)
end
tree:SetEvtHandlerEnabled(true)
end
tree:Connect( wx.wxEVT_COMMAND_TREE_ITEM_EXPANDING,
function( event )
local empty = ""
local function renameItem(itemsrc, target)
local isdir = tree:GetItemImage(itemsrc) == IMG_DIRECTORY
local isnew = tree:GetItemText(itemsrc) == empty
local source = tree:GetItemFullName(itemsrc)
local fn = wx.wxFileName(target)
if wx.wxFileName(source):SameAs(fn) then return false end
local docs = {}
if not isnew then -- find if source is already opened in the editor
docs = isdir
and ide:FindDocumentsByPartialPath(source)
or {ide:FindDocument(source)}
for _, doc in ipairs(docs) do
if SaveModifiedDialog(doc.editor, true) == wx.wxID_CANCEL then return end
end
end
-- check if existing file/dir is going to be overwritten
if (wx.wxFileExists(target) or wx.wxDirExists(target))
and not ApproveFileOverwrite() then return false end
if not fn:Mkdir(tonumber(755,8), wx.wxPATH_MKDIR_FULL) then
ReportError(TR("Unable to create directory '%s'."):format(target))
return false
end
if isnew then -- new directory or file; create manually
if (isdir and not wx.wxFileName.DirName(target):Mkdir(tonumber(755,8), wx.wxPATH_MKDIR_FULL))
or (not isdir and not FileWrite(target, "")) then
ReportError(TR("Unable to create file '%s'."):format(target))
return false
end
else -- existing directory or file; rename/move it
local ok, err = FileRename(source, target)
if not ok then
ReportError(TR("Unable to rename file '%s'."):format(source)
.."\nError: "..err)
return false
end
end
refreshAncestors(tree:GetItemParent(itemsrc))
-- load file(s) into the same editor (if any); will also refresh the tree
if #docs > 0 then
for _, doc in ipairs(docs) do
local fullpath = doc.filePath
doc.filePath = nil -- remove path to avoid "file no longer exists" message
-- when moving folders, /foo/bar/file.lua can be replaced with
-- /foo/baz/bar/file.lua, so change /foo/bar to /foo/baz/bar
LoadFile(fullpath:gsub(q(source), target), doc.editor)
end
else -- refresh the tree and select the new item
local itemdst = findItem(tree, target)
if itemdst then
refreshAncestors(tree:GetItemParent(itemdst))
tree:SelectItem(itemdst)
tree:EnsureVisible(itemdst)
tree:SetScrollPos(wx.wxHORIZONTAL, 0, true)
end
end
return true
end
local function deleteItem(item_id)
local isdir = tree:GetItemImage(item_id) == IMG_DIRECTORY
local source = tree:GetItemFullName(item_id)
if isdir and FileSysHasContent(source..pathsep) then return false end
if wx.wxMessageBox(
TR("Do you want to delete '%s'?"):format(source),
GetIDEString("editormessage"),
wx.wxYES_NO + wx.wxCENTRE, ide.frame) ~= wx.wxYES then return false end
if isdir then
wx.wxRmdir(source)
else
local doc = ide:FindDocument(source)
if doc then ClosePage(doc.index) end
wx.wxRemoveFile(source)
end
refreshAncestors(tree:GetItemParent(item_id))
return true
end
tree:Connect(wx.wxEVT_COMMAND_TREE_ITEM_EXPANDING,
function (event)
local item_id = event:GetItem()
local dir = tree:GetItemFullName(item_id)
if wx.wxDirExists(dir) then treeAddDir(tree,item_id,dir) -- refresh folder
else refreshAncestors(tree:GetItemParent(item_id)) end -- stale content
return true
end)
tree:Connect( wx.wxEVT_COMMAND_TREE_ITEM_ACTIVATED,
function( event )
tree:Connect(wx.wxEVT_COMMAND_TREE_ITEM_ACTIVATED,
function (event)
local item_id = event:GetItem()
local name = tree:GetItemFullName(item_id)
-- refresh the folder
@@ -145,12 +273,91 @@ local function treeSetConnectorsAndIcons(tree)
end
end)
-- handle context menu
tree:Connect( wx.wxEVT_COMMAND_TREE_ITEM_MENU,
function( event )
tree:Connect(wx.wxEVT_COMMAND_TREE_ITEM_MENU,
function (event)
local item_id = event:GetItem()
tree:SelectItem(item_id)
local menu = wx.wxMenu()
menu:Append(ID_SHOWLOCATION, TR("Show Location"))
local menu = wx.wxMenu {
{ ID_NEWFILE, TR("New &File") },
{ ID_NEWDIRECTORY, TR("&New Directory") },
{ },
{ ID_RENAMEFILE, TR("&Rename")..KSC(ID_RENAMEFILE) },
{ ID_DELETEFILE, TR("&Delete")..KSC(ID_DELETEFILE) },
{ },
{ ID_OPENEXTENSION, TR("Open With Default Program") },
{ ID_COPYFULLPATH, TR("Copy Full Path") },
{ ID_SHOWLOCATION, TR("Show Location") },
}
local function addItem(item_id, name, image)
local isdir = tree:GetItemImage(item_id) == IMG_DIRECTORY
local parent = isdir and item_id or tree:GetItemParent(item_id)
if isdir then tree:Expand(item_id) end -- expand to populate if needed
local item = tree:PrependItem(parent, name, image)
tree:SetItemHasChildren(parent, true)
-- temporarily disable expand as we don't need this node populated
tree:SetEvtHandlerEnabled(false)
tree:EnsureVisible(item)
tree:SetEvtHandlerEnabled(true)
return item
end
-- disable Delete on non-empty directories
local isdir = tree:GetItemImage(item_id) == IMG_DIRECTORY
if isdir then
local source = tree:GetItemFullName(item_id)
menu:Enable(ID_DELETEFILE, not FileSysHasContent(source..pathsep))
menu:Enable(ID_OPENEXTENSION, false)
else
local fname = tree:GetItemText(item_id)
local ext = '.'..wx.wxFileName(fname):GetExt()
local ft = wx.wxTheMimeTypesManager:GetFileTypeFromExtension(ext)
menu:Enable(ID_OPENEXTENSION, ft and #ft:GetOpenCommand("") > 0)
end
tree:Connect(ID_NEWFILE, wx.wxEVT_COMMAND_MENU_SELECTED,
function()
tree:EditLabel(addItem(item_id, empty, IMG_FILE_OTHER))
end)
tree:Connect(ID_NEWDIRECTORY, wx.wxEVT_COMMAND_MENU_SELECTED,
function()
tree:EditLabel(addItem(item_id, empty, IMG_DIRECTORY))
end)
tree:Connect(ID_RENAMEFILE, wx.wxEVT_COMMAND_MENU_SELECTED,
function() tree:EditLabel(item_id) end)
tree:Connect(ID_DELETEFILE, wx.wxEVT_COMMAND_MENU_SELECTED,
function() deleteItem(item_id) end)
tree:Connect(ID_COPYFULLPATH, wx.wxEVT_COMMAND_MENU_SELECTED,
function()
local tdo = wx.wxTextDataObject(tree:GetItemFullName(item_id))
if wx.wxClipboard:Get():Open() then
wx.wxClipboard:Get():SetData(tdo)
wx.wxClipboard:Get():Close()
end
end)
tree:Connect(ID_OPENEXTENSION, wx.wxEVT_COMMAND_MENU_SELECTED,
function()
local fname = tree:GetItemFullName(item_id)
local ext = '.'..wx.wxFileName(fname):GetExt()
local ft = wx.wxTheMimeTypesManager:GetFileTypeFromExtension(ext)
if ft then
local cmd = ft:GetOpenCommand(fname:gsub('"','\\"'))
local pid = wx.wxExecute(cmd, wx.wxEXEC_ASYNC)
if ide.osname == 'Windows' and pid and pid > 0 then
-- some programs on Windows (for example, PhotoViewer) accept
-- files with spaces in names ONLY if they are not in quotes.
-- wait for the process that failed to open file to finish
-- and retry without quotes.
wx.wxMilliSleep(250) -- 250ms seems enough; picked empirically.
if not wx.wxProcess.Exists(pid) then
local cmd = ft:GetOpenCommand(""):gsub('""%s*$', '')..fname
wx.wxExecute(cmd, wx.wxEXEC_ASYNC)
end
end
end
end)
tree:Connect(ID_SHOWLOCATION, wx.wxEVT_COMMAND_MENU_SELECTED,
function() ShowLocation(tree:GetItemFullName(item_id)) end)
@@ -159,11 +366,15 @@ local function treeSetConnectorsAndIcons(tree)
tree:PopupMenu(menu)
end)
-- toggle a folder on a single click
tree:Connect( wx.wxEVT_LEFT_DOWN,
function( event )
local item_id = tree:HitTest(event:GetPosition())
-- only toggle if this is a folder and the click is on the label
if item_id and tree:GetItemImage(item_id) == IMG_DIRECTORY then
tree:Connect(wx.wxEVT_LEFT_DOWN,
function (event)
-- only toggle if this is a folder and the click is on the item line
-- (exclude the label as it's used for renaming and dragging)
local mask = wx.wxTREE_HITTEST_ONITEMINDENT
+ wx.wxTREE_HITTEST_ONITEMICON + wx.wxTREE_HITTEST_ONITEMRIGHT
local item_id, flags = tree:HitTest(event:GetPosition())
if item_id and tree:GetItemImage(item_id) == IMG_DIRECTORY
and bit.band(flags, mask) > 0 then
tree:Toggle(item_id)
tree:SelectItem(item_id)
else
@@ -171,6 +382,57 @@ local function treeSetConnectorsAndIcons(tree)
end
return true
end)
tree:Connect(wx.wxEVT_COMMAND_TREE_END_LABEL_EDIT,
function (event)
-- veto the event to keep the original label intact as the tree
-- is going to be refreshed with the correct names.
event:Veto()
local itemsrc = event:GetItem()
if itemsrc == tree:GetRootItem() then return end -- don't edit root
local sourcedir = tree:GetItemFullName(tree:GetItemParent(itemsrc))
local label = event:GetLabel():gsub("^%s+$","") -- clean all spaces
local target = MergeFullPath(sourcedir, label)
if event:IsEditCancelled() or label == empty
or target and not renameItem(itemsrc, target)
then refreshAncestors(tree:GetItemParent(itemsrc)) end
end)
tree:Connect(wx.wxEVT_KEY_DOWN,
function (event)
local item = tree:GetSelection()
if item:IsOk() then
local keycode = event:GetKeyCode()
if keycode == wx.WXK_F2 then return tree:EditLabel(item)
elseif keycode == wx.WXK_DELETE then return deleteItem(item)
elseif keycode == wx.WXK_RETURN or keycode == wx.WXK_NUMPAD_ENTER then
tree:Toggle(item) end
end
event:Skip()
end)
local itemsrc
tree:Connect(wx.wxEVT_COMMAND_TREE_BEGIN_DRAG,
function (event)
if event:GetItem() ~= tree:GetRootItem() then
itemsrc = event:GetItem()
event:Allow()
end
end)
tree:Connect(wx.wxEVT_COMMAND_TREE_END_DRAG,
function (event)
local itemdst = event:GetItem()
if not itemdst:IsOk() then return end
-- check if itemdst is a folder
local target = tree:GetItemFullName(itemdst)
if wx.wxDirExists(target) then
local source = tree:GetItemFullName(itemsrc)
-- check if moving the directory and target is a subfolder of source
if (target..pathsep):find("^"..q(source)..pathsep) then return end
renameItem(itemsrc, MergeFullPath(target, tree:GetItemText(itemsrc)))
end
end)
end
-- project
@@ -188,7 +450,8 @@ local projbutton = wx.wxButton(projpanel, ID_PROJECTDIRCHOOSE,
local projtree = wx.wxTreeCtrl(projpanel, wx.wxID_ANY,
wx.wxDefaultPosition, wx.wxDefaultSize,
wx.wxTR_HAS_BUTTONS + wx.wxTR_SINGLE + wx.wxTR_LINES_AT_ROOT)
wx.wxTR_HAS_BUTTONS + wx.wxTR_SINGLE + wx.wxTR_LINES_AT_ROOT
+ wx.wxTR_EDIT_LABELS)
-- use the same font in the combobox as is used in the filetree
projtree:SetFont(ide.font.fNormal)
@@ -230,8 +493,6 @@ treeSetConnectorsAndIcons(projtree)
-- proj functions
-- ---------------
local function q(s) return s:gsub('([%(%)%.%%%+%-%*%?%[%^%$%]])','%%%1') end
local function abbreviateProjList(projdirlist)
filetree.projdirmap = {}
local sep = "\t"
@@ -265,6 +526,8 @@ function filetree:updateProjectDir(newdir)
if filetree.projdir and #filetree.projdir > 0 then
PackageEventHandle("onProjectClose", filetree.projdir) end
PackageEventHandle("onProjectPreLoad", newdir)
if ide.config.projectautoopen and filetree.projdir then
StoreRestoreProjectTabs(filetree.projdir, newdir)
end
@@ -272,8 +535,6 @@ function filetree:updateProjectDir(newdir)
filetree.projdir = newdir
filetree.projdirpartmap = {}
PackageEventHandle("onProjectLoad", filetree.projdir)
PrependStringToArray(
filetree.projdirlist,
newdir,
@@ -294,6 +555,8 @@ function filetree:updateProjectDir(newdir)
FileTreeMarkSelected(ide.openDocuments[id].filePath)
end
end
PackageEventHandle("onProjectLoad", newdir)
end
projpanel.projbutton = projbutton
@@ -316,44 +579,6 @@ function FileTreeGetProjects()
return filetree.projdirlist
end
local function findItem(tree, match)
local node = projtree:GetRootItem()
local label = tree:GetItemText(node)
local s, e
if iscaseinsensitive then
s, e = string.find(match:lower(), label:lower(), 1, true)
else
s, e = string.find(match, label, 1, true)
end
if not s or s ~= 1 then return end
for token in string.gmatch(string.sub(match,e+1), "[^%"..pathsep.."]+") do
local data = tree:GetItemData(node)
local cache = data and data:GetData()
if cache and cache[iscaseinsensitive and token:lower() or token] then
node = cache[iscaseinsensitive and token:lower() or token]
else
-- token is missing; may need to re-scan the folder; maybe new file
local dir = tree:GetItemFullName(node)
treeAddDir(tree,node,dir)
local item, cookie = tree:GetFirstChild(node)
while true do
if not item:IsOk() then return end -- not found
if tree:GetItemText(item) == token then
node = item
break
end
item, cookie = tree:GetNextChild(node, cookie)
end
end
end
-- this loop exits only when a match is found
return node
end
local curr_file
function FileTreeMarkSelected(file)
if not file or not filetree.projdir or #filetree.projdir == 0 then return end
@@ -390,9 +615,10 @@ function FileTreeFindByPartialName(name)
-- an abbreviated path (as generated by stack traces);
-- remove starting "..." if any and escape
local pattern = q(name:gsub("^%.%.%.","")):gsub("[\\/]", "[\\/]").."$"
local lpattern = pattern:lower()
for _, file in ipairs(FileSysGetRecursive(filetree.projdir, true)) do
if file:find(pattern) then
if file:find(pattern) or iscaseinsensitive and file:lower():find(lpattern) then
filetree.projdirpartmap[name] = file
return file
end

View File

@@ -95,7 +95,7 @@ function findReplace:GetSelectedString()
local startSel = editor:GetSelectionStart()
local endSel = editor:GetSelectionEnd()
if (startSel ~= endSel) and (editor:LineFromPosition(startSel) == editor:LineFromPosition(endSel)) then
findReplace.findText = editor:GetSelectedText()
findReplace.findText = editor:GetTextRange(startSel, endSel)
return true
end
end
@@ -362,7 +362,7 @@ function findReplace:createDialog(replace,infiles)
local replaceButton = wx.wxButton(findDialog, ID_REPLACE, infiles and replace and TR("&Replace All") or TR("&Replace"))
local replaceAllButton = nil
if (replace and not infiles) then
replaceAllButton = wx.wxButton(findDialog, ID_REPLACE_ALL, TR("Replace &All"))
replaceAllButton = wx.wxButton(findDialog, ID_REPLACE_ALL, TR("Replace A&ll"))
end
local cancelButton = wx.wxButton(findDialog, wx.wxID_CANCEL, TR("Cancel"))
@@ -594,8 +594,9 @@ function findReplace:createDialog(replace,infiles)
-- if on OSX then select the current value of the default dropdown
-- and don't set the default as it doesn't make Enter to work, but
-- prevents associated hotkey (Cmd-F) from working (wx2.9.5).
if ide.osname == 'Macintosh' then
findTextCombo:SetSelection(0, #findTextCombo:GetValue())
if mac then
findTextCombo:SetSelection(-1, -1)
findTextCombo:SetFocus() -- force focus on the Find
else
findButton:SetDefault()
end

View File

@@ -53,7 +53,7 @@ local function createFrame()
statusBar:SetStatusStyles({wx.wxSB_FLAT, wx.wxSB_FLAT, wx.wxSB_FLAT,
wx.wxSB_FLAT, wx.wxSB_FLAT, wx.wxSB_FLAT})
statusBar:SetStatusWidths(
{-1, section_width*6, section_width, section_width, section_width*4, section_width*4})
{-1, section_width*6, section_width, section_width, section_width*5, section_width*4})
statusBar:SetStatusText(GetIDEString("statuswelcome"))
local mgr = wxaui.wxAuiManager()
@@ -91,7 +91,7 @@ local function createToolBar(frame)
toolBar:AddTool(ID_REPLACE, "Replace", getBitmap(wx.wxART_FIND_AND_REPLACE, wx.wxART_TOOLBAR, toolBmpSize), TR("Find and replace text")..SCinB(ID_REPLACE))
if ide.app.createbitmap then -- custom handler should handle all bitmaps
toolBar:AddSeparator()
toolBar:AddTool(ID_STARTDEBUG, "Start Debugging", getBitmap("wxART_DEBUG_START", wx.wxART_TOOLBAR, toolBmpSize), TR("Start debugging")..SCinB(ID_STARTDEBUG))
toolBar:AddTool(ID_STARTDEBUG, "Start Debugging", getBitmap("wxART_DEBUG_START", wx.wxART_TOOLBAR, toolBmpSize), TR("Start or Continue debugging")..SCinB(ID_STARTDEBUG))
toolBar:AddTool(ID_STOPDEBUG, "Stop Debugging", getBitmap("wxART_DEBUG_STOP", wx.wxART_TOOLBAR, toolBmpSize), TR("Stop the currently running process")..SCinB(ID_STOPDEBUG))
toolBar:AddTool(ID_BREAK, "Break", getBitmap("wxART_DEBUG_BREAK", wx.wxART_TOOLBAR, toolBmpSize), TR("Break execution at the next executed line of code")..SCinB(ID_BREAK))
toolBar:AddTool(ID_STEP, "Step into", getBitmap("wxART_DEBUG_STEP_INTO", wx.wxART_TOOLBAR, toolBmpSize), TR("Step into")..SCinB(ID_STEP))
@@ -137,7 +137,15 @@ local function createNotebook(frame)
and debug:traceback():find("'AddPage'"))
if doc and event:GetOldSelection() ~= -1 and not double then
SetEditorSelection(notebook:GetSelection()) end
-- switching between editor tabs doesn't trigger KILL_FOCUS events
-- on OSX (http://trac.wxwidgets.org/ticket/14142); trigger manually
if ide.osname == 'Macintosh' then
local win = notebook:GetPage(event:GetOldSelection())
local ev = wx.wxFocusEvent(wx.wxEVT_KILL_FOCUS)
win:GetEventHandler():ProcessEvent(ev)
end
SetEditorSelection(notebook:GetSelection())
end
end)
notebook:Connect(wxaui.wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE,
@@ -157,6 +165,8 @@ local function createNotebook(frame)
local editor = GetEditor(page)
if editor then ide.openDocuments[editor:GetId()].index = page end
end
-- select the content of the tab after drag is done
SetEditorSelection(event:GetSelection())
event:Skip()
end)
end
@@ -173,15 +183,16 @@ local function createNotebook(frame)
-- save tab index the event is for
selection = notebook:GetPageIndex(tabctrl:GetPage(idx).window)
local menu = wx.wxMenu()
menu:Append(ID_CLOSE, TR("&Close Page"))
menu:Append(ID_CLOSEALL, TR("Close A&ll Pages"))
menu:Append(ID_CLOSEOTHER, TR("Close &Other Pages"))
menu:AppendSeparator()
menu:Append(ID_SAVE, TR("&Save"))
menu:Append(ID_SAVEAS, TR("Save &As..."))
menu:AppendSeparator()
menu:Append(ID_SHOWLOCATION, TR("Show Location"))
local menu = wx.wxMenu {
{ ID_CLOSE, TR("&Close Page") },
{ ID_CLOSEALL, TR("Close A&ll Pages") },
{ ID_CLOSEOTHER, TR("Close &Other Pages") },
{ },
{ ID_SAVE, TR("&Save") },
{ ID_SAVEAS, TR("Save &As...") },
{ },
{ ID_SHOWLOCATION, TR("Show Location") },
}
PackageEventHandle("onMenuEditorTab", menu, notebook, event, selection)

View File

@@ -9,27 +9,37 @@ function NewID()
return ID_IDCOUNTER
end
-- some Ubuntu versions (Ubuntu 13.10) ignore labels on stock menu IDs,
-- so don't use stock IDs on Linux
local linux = ide.osname == 'Unix'
-- File menu
ID_NEW = wx.wxID_NEW
ID_OPEN = wx.wxID_OPEN
ID_NEW = linux and NewID() or wx.wxID_NEW
ID_OPEN = linux and NewID() or wx.wxID_OPEN
ID_CLOSE = NewID()
ID_CLOSEALL = NewID()
ID_CLOSEOTHER = NewID()
ID_NEWFILE = NewID()
ID_NEWDIRECTORY = NewID()
ID_RENAMEFILE = NewID()
ID_DELETEFILE = NewID()
ID_OPENEXTENSION = NewID()
ID_COPYFULLPATH = NewID()
ID_SHOWLOCATION = NewID()
ID_SAVE = wx.wxID_SAVE
ID_SAVEAS = wx.wxID_SAVEAS
ID_SAVE = linux and NewID() or wx.wxID_SAVE
ID_SAVEAS = linux and NewID() or wx.wxID_SAVEAS
ID_SAVEALL = NewID()
ID_RECENTFILES = NewID()
ID_RECENTFILESPREV = NewID()
ID_RECENTFILESNEXT = NewID()
ID_EXIT = wx.wxID_EXIT
ID_EXIT = linux and NewID() or wx.wxID_EXIT
-- Edit menu
ID_CUT = wx.wxID_CUT
ID_COPY = wx.wxID_COPY
ID_PASTE = wx.wxID_PASTE
ID_SELECTALL = wx.wxID_SELECTALL
ID_UNDO = wx.wxID_UNDO
ID_REDO = wx.wxID_REDO
ID_CUT = linux and NewID() or wx.wxID_CUT
ID_COPY = linux and NewID() or wx.wxID_COPY
ID_PASTE = linux and NewID() or wx.wxID_PASTE
ID_SELECTALL = linux and NewID() or wx.wxID_SELECTALL
ID_UNDO = linux and NewID() or wx.wxID_UNDO
ID_REDO = linux and NewID() or wx.wxID_REDO
ID_SHOWTOOLTIP = NewID()
ID_AUTOCOMPLETE = NewID()
ID_AUTOCOMPLETEENABLE = NewID()
@@ -42,9 +52,11 @@ ID_PREFERENCES = NewID()
ID_PREFERENCESSYSTEM = NewID()
ID_PREFERENCESUSER = NewID()
-- Search menu
ID_FIND = wx.wxID_FIND
ID_FIND = linux and NewID() or wx.wxID_FIND
ID_FINDNEXT = NewID()
ID_FINDPREV = NewID()
ID_FINDSELECTNEXT = NewID()
ID_FINDSELECTPREV = NewID()
ID_REPLACE = NewID()
ID_FINDINFILES = NewID()
ID_REPLACEINFILES = NewID()
@@ -57,6 +69,7 @@ ID_VIEWCALLSTACK = NewID()
ID_VIEWWATCHWINDOW = NewID()
ID_VIEWDEFAULTLAYOUT = NewID()
ID_VIEWFULLSCREEN = NewID()
ID_VIEWMINIMIZE = NewID()
-- Project menu
ID_TOGGLEBREAKPOINT = NewID()
ID_COMPILE = NewID()
@@ -72,12 +85,13 @@ ID_STEPOUT = NewID()
ID_BREAK = NewID()
ID_TRACE = NewID()
ID_CLEAROUTPUT = NewID()
ID_COMMANDLINEPARAMETERS = NewID()
ID_INTERPRETER = NewID()
ID_PROJECTDIR = NewID()
ID_PROJECTDIRFROMFILE = NewID()
ID_PROJECTDIRCHOOSE = NewID()
-- Help menu
ID_ABOUT = wx.wxID_ABOUT
ID_ABOUT = linux and NewID() or wx.wxID_ABOUT
ID_HELPPROJECT = NewID()
ID_HELPDOCUMENTATION = NewID()
ID_HELPGETTINGSTARTED = NewID()

View File

@@ -36,6 +36,14 @@ function M.warnings_from_string(src, file)
return M.show_warnings(ast)
end
function AnalyzeFile(file)
local warn, err, line, pos = M.warnings_from_string(FileRead(file), file)
if err then
err = err:gsub("line %d+, char %d+", "syntax error")
end
return warn, err, line, pos
end
function M.show_warnings(top_ast)
local warnings = {}
local function warn(msg, linenum, path)
@@ -155,11 +163,9 @@ local frame = ide.frame
local menu = frame.menuBar:GetMenu(frame.menuBar:FindMenu(TR("&Project")))
-- insert after "Compile" item
for item = 0, menu:GetMenuItemCount()-1 do
if menu:FindItemByPosition(item):GetId() == ID_COMPILE then
menu:Insert(item+1, ID_ANALYZE, TR("Analyze")..KSC(ID_ANALYZE), TR("Analyze the source code"))
break
end
local _, compilepos = ide:FindMenuItem(menu, ID_COMPILE)
if compilepos then
menu:Insert(compilepos+1, ID_ANALYZE, TR("Analyze")..KSC(ID_ANALYZE), TR("Analyze the source code"))
end
local debugger = ide.debugger
@@ -191,7 +197,7 @@ frame:Connect(ID_ANALYZE, wx.wxEVT_COMMAND_MENU_SELECTED,
function ()
ActivateOutput()
local editor = GetEditor()
if not analyzeProgram(editor) then CompileProgram(editor) end
if not analyzeProgram(editor) then CompileProgram(editor, { reportstats = false }) end
end)
frame:Connect(ID_ANALYZE, wx.wxEVT_UPDATE_UI,
function (event)

View File

@@ -52,6 +52,8 @@ ide.config.keymap = {
[ID_FIND] = "Ctrl-F",
[ID_FINDNEXT] = "F3",
[ID_FINDPREV] = "Shift-F3",
[ID_FINDSELECTNEXT] = "Ctrl-F3",
[ID_FINDSELECTPREV] = "Ctrl-Shift-F3",
[ID_REPLACE] = "Ctrl-R",
[ID_FINDINFILES] = "Ctrl-Shift-F",
[ID_REPLACEINFILES] = "Ctrl-Shift-R",
@@ -90,11 +92,33 @@ ide.config.keymap = {
-- Editor popup menu items
[ID_QUICKADDWATCH] = "",
[ID_QUICKEVAL] = "",
-- Filetree popup menu items
[ID_RENAMEFILE] = "F2",
[ID_DELETEFILE] = "Del",
}
function KSC(id, default)
-- this is only for the rare case of someone assigning a complete list
-- to ide.config.keymap.
local keymap = ide.config.keymap
return keymap[id] and "\t"..keymap[id] or default or ""
return (keymap[id] and "\t"..keymap[id]) or (default and "\t"..default) or ""
end
ide.config.editor.keymap = {
-- key, modifier, command, os: http://www.scintilla.org/ScintillaDoc.html#KeyboardCommands
-- Cmd+Left/Right moves to start/end of line
{wxstc.wxSTC_KEY_LEFT, wxstc.wxSTC_SCMOD_CTRL, wxstc.wxSTC_CMD_HOME, "Macintosh"},
{wxstc.wxSTC_KEY_RIGHT, wxstc.wxSTC_SCMOD_CTRL, wxstc.wxSTC_CMD_LINEEND, "Macintosh"},
-- Cmd+Shift+Left/Right selects to the beginning/end of the line
{wxstc.wxSTC_KEY_LEFT, wxstc.wxSTC_SCMOD_CTRL+wxstc.wxSTC_SCMOD_SHIFT, wxstc.wxSTC_CMD_HOMEEXTEND, "Macintosh"},
{wxstc.wxSTC_KEY_RIGHT, wxstc.wxSTC_SCMOD_CTRL+wxstc.wxSTC_SCMOD_SHIFT, wxstc.wxSTC_CMD_LINEENDEXTEND, "Macintosh"},
-- Cmd+Shift+Up/Down selects to the beginning/end of the text
{wxstc.wxSTC_KEY_UP, wxstc.wxSTC_SCMOD_CTRL+wxstc.wxSTC_SCMOD_SHIFT, wxstc.wxSTC_CMD_LINEUPEXTEND, "Macintosh"},
{wxstc.wxSTC_KEY_DOWN, wxstc.wxSTC_SCMOD_CTRL+wxstc.wxSTC_SCMOD_SHIFT, wxstc.wxSTC_CMD_LINEDOWNEXTEND, "Macintosh"},
-- Opt+Left/Right moves one word left (to the beginning)/right (to the end)
{wxstc.wxSTC_KEY_LEFT, wxstc.wxSTC_SCMOD_ALT, wxstc.wxSTC_CMD_WORDLEFT, "Macintosh"},
{wxstc.wxSTC_KEY_RIGHT, wxstc.wxSTC_SCMOD_ALT, wxstc.wxSTC_CMD_WORDRIGHTEND, "Macintosh"},
-- Opt+Shift+Left/Right selects one word left (to the beginning)/right (to the end)
{wxstc.wxSTC_KEY_LEFT, wxstc.wxSTC_SCMOD_ALT+wxstc.wxSTC_SCMOD_SHIFT, wxstc.wxSTC_CMD_WORDLEFTEXTEND, "Macintosh"},
{wxstc.wxSTC_KEY_RIGHT, wxstc.wxSTC_SCMOD_ALT+wxstc.wxSTC_SCMOD_SHIFT, wxstc.wxSTC_CMD_WORDRIGHTENDEXTEND, "Macintosh"},
}

View File

@@ -38,7 +38,7 @@ function MarkupAddStyles(styles)
end
end
local function q(s) return s:gsub('(.)','%%%1') end
local q = EscapeMagic
local MD_MARK_PTRN = '' -- combination of all markup marks that can start styling
for key in pairs(markup) do
@@ -94,6 +94,7 @@ end
local function ismarkup (tx)
local start = 1
local marksep = "[%s!%?%.,;:%(%)]"
while true do
-- find a separator first
local st,_,sep,more = string.find(tx, "(["..MD_MARK_PTRN.."])(.)", start)
@@ -121,9 +122,9 @@ local function ismarkup (tx)
s,e,cap = string.find(tx,"^("..qsep..nonspace..nonsep.."-"..nonspace..qsep..")", st)
if not s then s,e,cap = string.find(tx,"^("..qsep..nonspace..qsep..")", st) end
end
if s and -- selected markup is surrounded by spaces or punctuation
(s == start or tx:sub(s-1, s-1):match("[%s%p]")) and
(e-s == #tx-1 or tx:sub(e+1, e+1):match("[%s%p]"))
if s and -- selected markup is surrounded by spaces or punctuation marks
(s == 1 or tx:sub(s-1, s-1):match(marksep)) and
(e == #tx or tx:sub(e+1, e+1):match(marksep))
then return s,e,cap,sep end
start = st+1
end

View File

@@ -47,17 +47,19 @@ local function getControlWithFocus()
or ide.osname == 'Macintosh' and
ctrl:GetParent():GetId() == e:GetId()) then editor = e end
end
return editor
return editor or nil
end
function OnUpdateUIEditMenu(event)
local function onUpdateUIEditMenu(event)
local editor = getControlWithFocus()
if editor == nil then event:Enable(false); return end
local cancomment = pcall(function() return editor.spec end) and editor.spec
and editor.spec.linecomment and true or false
local alwaysOn = { [ID_SELECTALL] = true, [ID_FOLD] = ide.config.editor.fold,
-- allow Cut and Copy commands as these work on a line if no selection
[ID_COPY] = true, [ID_CUT] = true,
[ID_COMMENT] = true, [ID_AUTOCOMPLETE] = true, [ID_SORT] = true}
[ID_COMMENT] = cancomment, [ID_AUTOCOMPLETE] = true, [ID_SORT] = true}
local menu_id = event:GetId()
local enable =
menu_id == ID_PASTE and editor:CanPaste() or
@@ -65,7 +67,11 @@ function OnUpdateUIEditMenu(event)
menu_id == ID_REDO and editor:CanRedo() or
alwaysOn[menu_id]
-- wxComboBox doesn't have SELECT ALL, so disable it
if editor:GetClassInfo():GetClassName() == 'wxComboBox'
-- editor:GetClassInfo mysteriously fails on Ubuntu 13.10 (earlier versions
-- are okay), which indicates that the menu item is checked after editor
-- is already closed, so the first pcall() check should protect against that.
if pcall(function() editor:GetId() end)
and editor:GetClassInfo():GetClassName() == 'wxComboBox'
and menu_id == ID_SELECTALL then enable = false end
event:Enable(enable)
end
@@ -96,7 +102,7 @@ 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)
frame:Connect(event, wx.wxEVT_UPDATE_UI, onUpdateUIEditMenu)
end
local function generateConfigMessage(type)
@@ -146,7 +152,7 @@ frame:Connect(ID_AUTOCOMPLETE, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
EditorAutoComplete(GetEditor())
end)
frame:Connect(ID_AUTOCOMPLETE, wx.wxEVT_UPDATE_UI, OnUpdateUIEditMenu)
frame:Connect(ID_AUTOCOMPLETE, wx.wxEVT_UPDATE_UI, onUpdateUIEditMenu)
frame:Connect(ID_AUTOCOMPLETEENABLE, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
@@ -156,6 +162,8 @@ frame:Connect(ID_AUTOCOMPLETEENABLE, wx.wxEVT_COMMAND_MENU_SELECTED,
frame:Connect(ID_COMMENT, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
local editor = GetEditor()
local lc = editor.spec.linecomment
if not lc then return end
-- capture the current position in line to restore later
local curline = editor:GetCurrentLine()
@@ -168,7 +176,6 @@ frame:Connect(ID_COMMENT, wx.wxEVT_COMMAND_MENU_SELECTED,
local eline = editor:LineFromPosition(esel)
local sel = ssel ~= esel
local rect = editor:SelectionIsRectangle()
local lc = editor.spec.linecomment
local qlc = lc:gsub(".", "%%%1")
-- figure out how to toggle comments; if there is at least one non-empty
@@ -212,7 +219,7 @@ frame:Connect(ID_COMMENT, wx.wxEVT_COMMAND_MENU_SELECTED,
+ math.max(0, curpos+#editor:GetLine(curline)-curlen))
end
end)
frame:Connect(ID_COMMENT, wx.wxEVT_UPDATE_UI, OnUpdateUIEditMenu)
frame:Connect(ID_COMMENT, wx.wxEVT_UPDATE_UI, onUpdateUIEditMenu)
frame:Connect(ID_SORT, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
@@ -230,10 +237,10 @@ 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, onUpdateUIEditMenu)
frame:Connect(ID_FOLD, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
FoldSome()
end)
frame:Connect(ID_FOLD, wx.wxEVT_UPDATE_UI, OnUpdateUIEditMenu)
frame:Connect(ID_FOLD, wx.wxEVT_UPDATE_UI, onUpdateUIEditMenu)

View File

@@ -8,7 +8,8 @@ local frame = ide.frame
local menuBar = frame.menuBar
local mobdebug = require "mobdebug"
local url = "http://download.zerobrane.com/zerobranestudio-"
local product = GetIDEString("help", "zerobranestudio")
local url = "http://zerobrane.com/r/"..product.."-"
local urls = {
[ID_HELPPROJECT] = "main",
[ID_HELPDOCUMENTATION] = "documentation",

View File

@@ -16,7 +16,7 @@ local debugTab = {
{ ID_RUN, TR("&Run")..KSC(ID_RUN), TR("Execute the current project/file") },
{ ID_RUNNOW, TR("Run as Scratchpad")..KSC(ID_RUNNOW), TR("Execute the current project/file and keep updating the code to see immediate results"), wx.wxITEM_CHECK },
{ ID_COMPILE, TR("&Compile")..KSC(ID_COMPILE), TR("Compile the current file") },
{ ID_STARTDEBUG, TR("Start &Debugging")..KSC(ID_STARTDEBUG), TR("Start debugging") },
{ ID_STARTDEBUG, TR("Start &Debugging")..KSC(ID_STARTDEBUG), TR("Start or continue debugging") },
{ ID_ATTACHDEBUG, TR("&Start Debugger Server")..KSC(ID_ATTACHDEBUG), TR("Allow external process to start debugging") },
{ },
{ ID_STOPDEBUG, TR("S&top Debugging")..KSC(ID_STOPDEBUG), TR("Stop the currently running process") },
@@ -29,10 +29,11 @@ local debugTab = {
{ ID_TOGGLEBREAKPOINT, TR("Toggle Break&point")..KSC(ID_TOGGLEBREAKPOINT), TR("Toggle breakpoint") },
{ },
{ ID_CLEAROUTPUT, TR("C&lear Output Window")..KSC(ID_CLEAROUTPUT), TR("Clear the output window before compiling or debugging"), wx.wxITEM_CHECK },
{ ID_COMMANDLINEPARAMETERS, TR("Command Line Parameters...")..KSC(ID_COMMANDLINEPARAMETERS), TR("Provide command line parameters") },
}
local targetDirMenu = wx.wxMenu{
{ID_PROJECTDIRCHOOSE, TR("Choose ...")..KSC(ID_PROJECTDIRCHOOSE), TR("Choose a project directory")},
{ID_PROJECTDIRCHOOSE, TR("Choose...")..KSC(ID_PROJECTDIRCHOOSE), TR("Choose a project directory")},
{ID_PROJECTDIRFROMFILE, TR("Set From Current File")..KSC(ID_PROJECTDIRFROMFILE), TR("Set project directory from current file")},
}
local targetMenu = wx.wxMenu({})
@@ -54,9 +55,10 @@ local function selectInterpreter(id)
menuBar:Check(id, true)
menuBar:Enable(id, false)
if ide.interpreter and ide.interpreter ~= interpreters[id] then
local changed = ide.interpreter ~= interpreters[id]
if ide.interpreter and changed then
PackageEventHandle("onInterpreterClose", ide.interpreter) end
if interpreters[id] and ide.interpreter ~= interpreters[id] then
if interpreters[id] and changed then
PackageEventHandle("onInterpreterLoad", interpreters[id]) end
ide.interpreter = interpreters[id]
@@ -64,7 +66,7 @@ local function selectInterpreter(id)
DebuggerShutdown()
ide.frame.statusBar:SetStatusText(ide.interpreter.name or "", 5)
ReloadLuaAPI()
if changed then ReloadLuaAPI() end
end
function ProjectSetInterpreter(name)
@@ -176,7 +178,7 @@ local function getNameToRun(skipcheck)
editor.spec.apitype == "lua" and
(not skipcheck) and
(not ide.interpreter.skipcompile) and
(not CompileProgram(editor, true)) then
(not CompileProgram(editor, { reportstats = false })) then
return
end
@@ -396,6 +398,17 @@ frame:Connect(ID_BREAK, wx.wxEVT_UPDATE_UI,
or (debugger.scratchpad and not debugger.scratchpad.paused)))
end)
frame:Connect(ID_COMMANDLINEPARAMETERS, wx.wxEVT_COMMAND_MENU_SELECTED,
function ()
local params = wx.wxGetTextFromUser(TR("Enter command line parameters (use Cancel to clear)"),
TR("Command line parameters"), ide.config.arg.any or "")
ide.config.arg.any = params and #params > 0 and params or nil
end)
frame:Connect(ID_COMMANDLINEPARAMETERS, wx.wxEVT_UPDATE_UI,
function (event)
event:Enable(ide.interpreter and ide.interpreter.takeparameters and true or false)
end)
frame:Connect(wx.wxEVT_IDLE,
function(event)
if (debugger.update) then debugger.update() end

View File

@@ -13,6 +13,8 @@ local findMenu = wx.wxMenu{
{ ID_FIND, TR("&Find")..KSC(ID_FIND), TR("Find text") },
{ ID_FINDNEXT, TR("Find &Next")..KSC(ID_FINDNEXT), TR("Find the next text occurrence") },
{ ID_FINDPREV, TR("Find &Previous")..KSC(ID_FINDPREV), TR("Find the earlier text occurence") },
{ ID_FINDSELECTNEXT, TR("Select and Find Next")..KSC(ID_FINDSELECTNEXT), TR("Select the word under cursor and find its next occurrence") },
{ ID_FINDSELECTPREV, TR("Select and Find Previous")..KSC(ID_FINDSELECTPREV), TR("Select the word under cursor and find its previous occurrence") },
{ ID_REPLACE, TR("&Replace")..KSC(ID_REPLACE), TR("Find and replace text") },
{ },
{ ID_FINDINFILES, TR("Find &In Files")..KSC(ID_FINDINFILES), TR("Find text in files") },
@@ -22,19 +24,19 @@ local findMenu = wx.wxMenu{
}
menuBar:Append(findMenu, TR("&Search"))
function OnUpdateUISearchMenu(event) event:Enable(GetEditor() ~= nil) end
local function onUpdateUISearchMenu(event) event:Enable(GetEditor() ~= nil) end
frame:Connect(ID_FIND, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
findReplace:Show(false)
end)
frame:Connect(ID_FIND, wx.wxEVT_UPDATE_UI, OnUpdateUISearchMenu)
frame:Connect(ID_FIND, wx.wxEVT_UPDATE_UI, onUpdateUISearchMenu)
frame:Connect(ID_REPLACE, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
findReplace:Show(true)
end)
frame:Connect(ID_REPLACE, wx.wxEVT_UPDATE_UI, OnUpdateUISearchMenu)
frame:Connect(ID_REPLACE, wx.wxEVT_UPDATE_UI, onUpdateUISearchMenu)
frame:Connect(ID_FINDINFILES, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
@@ -54,12 +56,14 @@ frame:Connect(ID_FINDNEXT, wx.wxEVT_COMMAND_MENU_SELECTED,
editor:SetMainSelection(selection)
editor:EnsureCaretVisible()
else
findReplace:GetSelectedString()
findReplace:FindString()
if findReplace:GetSelectedString() or findReplace:HasText() then
findReplace:FindString()
else
findReplace:Show(false)
end
end
end)
frame:Connect(ID_FINDNEXT, wx.wxEVT_UPDATE_UI,
function (event) event:Enable(findReplace:GetSelectedString() or findReplace:HasText()) end)
frame:Connect(ID_FINDNEXT, wx.wxEVT_UPDATE_UI, onUpdateUISearchMenu)
frame:Connect(ID_FINDPREV, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
@@ -70,12 +74,58 @@ frame:Connect(ID_FINDPREV, wx.wxEVT_COMMAND_MENU_SELECTED,
editor:SetMainSelection(selection)
editor:EnsureCaretVisible()
else
findReplace:GetSelectedString()
if findReplace:GetSelectedString() or findReplace:HasText() then
findReplace:FindString(true) -- search up
else
findReplace:Show(false)
end
end
end)
frame:Connect(ID_FINDPREV, wx.wxEVT_UPDATE_UI, onUpdateUISearchMenu)
-- Select and Find behaves like Find if there is a current selection;
-- if not, it selects a word under cursor (if any) and does find.
local function selectWordUnderCaret(editor)
local pos = editor:GetCurrentPos()
local text = editor:GetTextRange( -- try to select a word under caret
editor:WordStartPosition(pos, true), editor:WordEndPosition(pos, true))
return #text > 0 and text or editor:GetTextRange( -- try to select a non-word under caret
editor:WordStartPosition(pos, false), editor:WordEndPosition(pos, false))
end
frame:Connect(ID_FINDSELECTNEXT, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
local editor = GetEditor()
if editor:GetSelectionStart() ~= editor:GetSelectionEnd() then
ide.frame:AddPendingEvent(
wx.wxCommandEvent(wx.wxEVT_COMMAND_MENU_SELECTED, ID_FINDNEXT))
return
end
local text = selectWordUnderCaret(editor)
if #text > 0 then
findReplace.findText = text
findReplace:FindString()
end
end)
frame:Connect(ID_FINDSELECTNEXT, wx.wxEVT_UPDATE_UI, onUpdateUISearchMenu)
frame:Connect(ID_FINDSELECTPREV, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event)
local editor = GetEditor()
if editor:GetSelectionStart() ~= editor:GetSelectionEnd() then
ide.frame:AddPendingEvent(
wx.wxCommandEvent(wx.wxEVT_COMMAND_MENU_SELECTED, ID_FINDPREV))
return
end
local text = selectWordUnderCaret(editor)
if #text > 0 then
findReplace.findText = text
findReplace:FindString(true)
end
end)
frame:Connect(ID_FINDPREV, wx.wxEVT_UPDATE_UI,
function (event) event:Enable(findReplace:GetSelectedString() or findReplace:HasText()) end)
frame:Connect(ID_FINDSELECTPREV, wx.wxEVT_UPDATE_UI, onUpdateUISearchMenu)
-------------------- Find replace end
@@ -93,4 +143,4 @@ frame:Connect(ID_GOTOLINE, wx.wxEVT_COMMAND_MENU_SELECTED,
editor:GotoLine(linenum-1)
end
end)
frame:Connect(ID_GOTOLINE, wx.wxEVT_UPDATE_UI, OnUpdateUISearchMenu)
frame:Connect(ID_GOTOLINE, wx.wxEVT_UPDATE_UI, onUpdateUISearchMenu)

View File

@@ -3,8 +3,8 @@
local ide = ide
local frame = ide.frame
local menuBar = frame.menuBar
local openDocuments = ide.openDocuments
local unpack = table.unpack or unpack
--[=[
-- tool definition

View File

@@ -46,6 +46,9 @@ frame:Connect(ID_VIEWDEFAULTLAYOUT, wx.wxEVT_COMMAND_MENU_SELECTED,
uimgr:LoadPerspective(uimgr.defaultPerspective, true)
end)
frame:Connect(ID_VIEWMINIMIZE, wx.wxEVT_COMMAND_MENU_SELECTED,
function (event) ide.frame:Iconize(true) end)
frame:Connect(ID_VIEWFULLSCREEN, wx.wxEVT_COMMAND_MENU_SELECTED, function ()
pcall(function() ShowFullScreen(not frame:IsFullScreen()) end)
end)

View File

@@ -41,7 +41,7 @@ function DisplayOutputNoMarker(...)
local current = errorlog:GetReadOnly()
errorlog:SetReadOnly(false)
errorlog:AppendText(message)
errorlog:AppendText(FixUTF8(message, "\022"))
errorlog:EmptyUndoBuffer()
errorlog:SetReadOnly(current)
errorlog:GotoPos(errorlog:GetLength())
@@ -63,7 +63,10 @@ local textout = '' -- this is a buffer for any text sent to external scripts
function DetachChildProcess()
for _, custom in pairs(customprocs) do
if (custom and custom.proc) then custom.proc:Detach() end
-- since processes are detached, their END_PROCESS event is not going
-- to be called; call endcallback() manually if registered.
if custom.endcallback then custom.endcallback() end
if custom.proc then custom.proc:Detach() end
end
end
@@ -228,11 +231,11 @@ local function getStreams()
DisplayShell(str)
else
DisplayOutputNoMarker(str)
end
if str and ide.config.allowinteractivescript and
(getInputLine() > -1 or errorlog:GetReadOnly()) then
ActivateOutput()
updateInputMarker()
if str and ide.config.allowinteractivescript and
(getInputLine() > -1 or errorlog:GetReadOnly()) then
ActivateOutput()
updateInputMarker()
end
end
pfn = pfn and pfn()
end
@@ -430,3 +433,13 @@ errorlog:Connect(wxstc.wxEVT_STC_DO_DROP,
event:SetDragResult(wx.wxDragNone)
end
end)
if ide.config.outputshell.nomousezoom then
-- disable zoom using mouse wheel as it triggers zooming when scrolling
-- on OSX with kinetic scroll and then pressing CMD.
errorlog:Connect(wx.wxEVT_MOUSEWHEEL,
function (event)
if wx.wxGetKeyState(wx.WXK_CONTROL) then return end
event:Skip()
end)
end

View File

@@ -1,6 +1,8 @@
-- Copyright 2013 Paul Kulchenko, ZeroBrane LLC
local ide = ide
local iscaseinsensitive = wx.wxFileName("A"):SameAs(wx.wxFileName("a"))
local q = EscapeMagic
function PackageEventHandle(event, ...)
local success
@@ -59,14 +61,62 @@ function PackageRegister(file, ...)
return PackageEventHandleOne(file, "onRegister", ...)
end
function ide:GetRootPath() return GetPathWithSep(ide.editorFilename) end
function ide:GetPackagePath(packname)
return MergeFullPath(
ide.oshome and MergeFullPath(ide.oshome, '.zbstudio/') or ide:GetRootPath(),
MergeFullPath('packages', packname or '')
)
end
function ide:GetApp() return self.editorApp end
function ide:GetEditor(index) return GetEditor(index) end
function ide:GetMenuBar() return self.frame.menuBar end
function ide:GetStatusBar() return self.frame.statusBar end
function ide:GetToolBar() return self.frame.toolBar end
function ide:GetDebugger() return self.debugger end
function ide:GetMainFrame() return self.frame end
function ide:GetDocument(ed) return self.openDocuments[ed:GetId()] end
function ide:GetDocuments() return self.openDocuments end
function ide:FindMenuItem(menu, itemid)
for pos = 0, menu:GetMenuItemCount()-1 do
if menu:FindItemByPosition(pos):GetId() == itemid then
return menu:FindItemByPosition(pos), pos
end
end
return nil
end
function ide:FindDocument(path)
local fileName = wx.wxFileName(path)
for _, doc in pairs(ide.openDocuments) do
if doc.filePath and fileName:SameAs(wx.wxFileName(doc.filePath)) then
return doc
end
end
return
end
function ide:FindDocumentsByPartialPath(path)
local seps = "[\\/]"
-- add trailing path separator to make sure full directory match
if not path:find(seps.."$") then path = path .. GetPathSeparator() end
local pattern = "^"..q(path):gsub(seps, seps)
local lpattern = pattern:lower()
local docs = {}
for _, doc in pairs(ide.openDocuments) do
if doc.filePath
and (doc.filePath:find(pattern)
or iscaseinsensitive and doc.filePath:lower():find(lpattern)) then
table.insert(docs, doc)
end
end
return docs
end
function ide:GetInterpreter() return self.interpreter end
function ide:GetInterpreters() return ide.interpreters end
function ide:GetConfig() return self.config end
function ide:GetOutput() return self.frame.bottomnotebook.errorlog end
function ide:GetEditorNotebook() return self.frame.notebook end
function ide:GetProject() return FileTreeGetDir() end
function ide:GetSetting(path, setting)
local settings = self.settings
@@ -97,3 +147,29 @@ function ide:AddAPI(type, name, api)
self.apis[type][name] = api
end
function ide:RemoveAPI(type, name) self.apis[type][name] = nil end
function ide:AddConsoleAlias(alias, table) return ShellSetAlias(alias, table) end
function ide:RemoveConsoleAlias(alias) return ShellSetAlias(alias, nil) end
function ide:AddMarker(...) return StylesAddMarker(...) end
function ide:GetMarker(marker) return StylesGetMarker(marker) end
function ide:RemoveMarker(marker) StylesRemoveMarker(marker) end
-- this provides a simple stack for saving/restoring current configuration
local configcache = {}
function ide:AddConfig(name, files)
if not name or configcache[name] then return end -- don't overwrite existing slots
configcache[name] = require('mobdebug').dump(ide.config, {nocode = true})
for _, file in pairs(files) do LoadLuaConfig(MergeFullPath(name, file)) end
ReApplySpecAndStyles() -- apply current config to the UI
end
function ide:RemoveConfig(name)
if not name or not configcache[name] then return end
local ok, res = LoadSafe(configcache[name])
if ok then ide.config = res
else
DisplayOutputLn(("Error while restoring configuration: '%s'."):format(res))
end
configcache[name] = nil -- clear the slot after use
ReApplySpecAndStyles() -- apply current config to the UI
end

View File

@@ -4,7 +4,11 @@ ide.proto.Document = {__index = {
GetFileName = function(self) return self.fileName end,
GetFilePath = function(self) return self.filePath end,
GetModTime = function(self) return self.modTime end,
GetEditor = function(self) return self.editor end,
GetTabIndex = function(self) return self.index end,
IsModified = function(self) return self.isModified end,
SetModified = function(self, modified) SetDocumentModified(self.editor:GetId(), modified) end,
SetTabText = function(self, text) SetDocumentModified(self.editor:GetId(), self.isModified, text) end,
}}
ide.proto.Plugin = {__index = {

View File

@@ -1,6 +1,7 @@
-- authors: Luxinia Dev (Eike Decker & Christoph Kubisch)
---------------------------------------------------------
local ide = ide
local unpack = table.unpack or unpack
--
-- shellbox - a lua testbed environment within the IDE
--
@@ -54,6 +55,9 @@ local function setPromptText(text)
out:SetTargetStart(length - string.len(getPromptText()))
out:SetTargetEnd(length)
out:ReplaceTarget(text)
-- refresh the output window to force recalculation of wrapped lines;
-- otherwise a wrapped part of the last line may not be visible.
out:Update(); out:Refresh()
out:GotoPos(out:GetLength())
end
@@ -142,13 +146,13 @@ local function shellPrint(marker, ...)
text = text .. tostring(x)..(i < cnt and "\t" or "")
end
-- add "\n" if it is missing
if text then text = text:gsub("\n$", "") .. "\n" end
if text then text = text:gsub("\n+$", "") .. "\n" end
local lines = out:GetLineCount()
local promptLine = isPrompt and getPromptLine() or nil
local insertLineAt = isPrompt and getPromptLine() or out:GetLineCount()-1
local insertAt = isPrompt and out:PositionFromLine(getPromptLine()) or out:GetLength()
out:InsertText(insertAt, text)
out:InsertText(insertAt, FixUTF8(text, function (s) return '\\'..string.byte(s) end))
local linesAdded = out:GetLineCount() - lines
if marker then
@@ -269,6 +273,12 @@ end
local env = createenv()
function ShellSetAlias(alias, table)
local value = env[alias]
env[alias] = table
return value
end
local function packResults(status, ...) return status, {...} end
local function executeShellCode(tx)
@@ -331,7 +341,7 @@ local function executeShellCode(tx)
res = {'nil'}
end
end
DisplayShell((table.unpack or unpack)(res))
DisplayShell(unpack(res))
end
end
end
@@ -384,8 +394,8 @@ out:Connect(wx.wxEVT_KEY_DOWN,
-- through multiline entry
if out:GetCurrentLine() > getPromptLine() then break end
-- if we are not on the caret line, then don't move
if not caretOnPromptLine() then return end
-- if we are not on the caret line, move normally
if not caretOnPromptLine() then break end
local promptText = getPromptText()
setPromptText(getNextHistoryLine(false, promptText))
@@ -396,7 +406,9 @@ out:Connect(wx.wxEVT_KEY_DOWN,
local totalLines = out:GetLineCount()-1
if out:GetCurrentLine() < totalLines then break end
-- if we are not on the caret line, move normally
if not caretOnPromptLine() then break end
local promptText = getPromptText()
setPromptText(getNextHistoryLine(true, promptText))
return
@@ -422,8 +434,6 @@ out:Connect(wx.wxEVT_KEY_DOWN,
elseif key == wx.WXK_ESCAPE then
setPromptText("")
return
elseif key == wx.WXK_LEFT or key == wx.WXK_NUMPAD_LEFT then
if not caretOnPromptLine(true) then return end
elseif key == wx.WXK_BACK then
if not caretOnPromptLine(true) then return end
elseif key == wx.WXK_DELETE or key == wx.WXK_NUMPAD_DELETE then
@@ -435,6 +445,7 @@ out:Connect(wx.wxEVT_KEY_DOWN,
or key == wx.WXK_PAGEDOWN or key == wx.WXK_NUMPAD_PAGEDOWN
or key == wx.WXK_END or key == wx.WXK_NUMPAD_END
or key == wx.WXK_HOME or key == wx.WXK_NUMPAD_HOME
or key == wx.WXK_LEFT or key == wx.WXK_NUMPAD_LEFT
or key == wx.WXK_RIGHT or key == wx.WXK_NUMPAD_RIGHT
or key == wx.WXK_SHIFT or key == wx.WXK_CONTROL
or key == wx.WXK_ALT then
@@ -479,7 +490,7 @@ local function inputEditable(line)
not (out:LineFromPosition(out:GetSelectionStart()) < getPromptLine())
end
-- new Scintilla changed the way markers move when the text is updated
-- new Scintilla (3.2.1) changed the way markers move when the text is updated
-- ticket: http://sourceforge.net/p/scintilla/bugs/939/
-- discussion: https://groups.google.com/forum/?hl=en&fromgroups#!topic/scintilla-interest/4giFiKG4VXo
if ide.wxver >= "2.9.5" then
@@ -517,4 +528,14 @@ out:Connect(wxstc.wxEVT_STC_DO_DROP,
end
end)
if ide.config.outputshell.nomousezoom then
-- disable zoom using mouse wheel as it triggers zooming when scrolling
-- on OSX with kinetic scroll and then pressing CMD.
out:Connect(wx.wxEVT_MOUSEWHEEL,
function (event)
if wx.wxGetKeyState(wx.WXK_CONTROL) then return end
event:Skip()
end)
end
displayShellIntro()

View File

@@ -51,7 +51,15 @@ if success then -- ok, server was started, we are solo
local filename = msg:match(protocol.client.requestloading:gsub("%%s","(.+)$"))
if filename then
RequestAttention()
if not LoadFile(filename, nil, true) then
local done = true
if wx.wxDirExists(filename) then
local dir = wx.wxFileName.DirName(filename)
dir:Normalize() -- turn into absolute path if needed
ProjectUpdateProjectDir(dir:GetFullPath())
else
done = LoadFile(filename, nil, true)
end
if not done then
DisplayOutputLn("Can't open requested file '"..filename.."'.")
end
end

View File

@@ -8,6 +8,7 @@
-- ---------------------------
-- fg foreground - {r,g,b} 0-255
-- bg background - {r,g,b} 0-255
-- alpha translucency - 0-255 (0 - transparent, 255 - opaque, 256 - opaque/faster)
-- sel color of the selected block - {r,g,b} 0-255 (only applies to folds)
-- u underline - boolean
-- b bold - boolean
@@ -18,6 +19,8 @@
-- hs turn hotspot on - true or {r,g,b} 0-255
-- v visibility for symbols of the current style - boolean
local unpack = table.unpack or unpack
function StylesGetDefault()
return {
-- lexer specific (inherit fg/bg from text)
@@ -48,12 +51,12 @@ function StylesGetDefault()
calltip = nil,
-- common special (need custom fg & bg)
calltipbg = nil,
sel = {bg = {192, 192, 192}},
caret = {fg = {0, 0, 0}},
caretlinebg = {bg = {240, 240, 230}},
fold = {fg = {90, 90, 80}, bg = {250, 250, 250}, sel = {90+96, 90, 80}},
whitespace = nil,
edge = {},
-- deprecated; allowed for backward compatibility in case someone does
-- fncall.fg = {...}
@@ -94,6 +97,18 @@ local markers = {
error = {6, wxstc.wxSTC_MARK_BACKGROUND, wx.wxBLACK, wx.wxColour(255, 220, 220)},
}
function StylesGetMarker(marker) return unpack(markers[marker] or {}) end
function StylesRemoveMarker(marker) markers[marker] = nil end
function StylesAddMarker(marker, ch, fg, bg)
local num = (markers[marker] or {})[1]
if not num then -- new marker; find the smallest available marker number
local nums = {}
for _, mark in pairs(markers) do nums[mark[1]] = true end
num = #nums + 1
if num > 24 then return end -- 24 markers with no pre-defined functions
end
markers[marker] = {num, ch, wx.wxColour(unpack(fg)), wx.wxColour(unpack(bg))}
return num
end
local function applymarker(editor,marker,clrfg,clrbg,clrsel)
if (clrfg) then editor:MarkerSetForeground(marker,clrfg) end
@@ -112,10 +127,28 @@ local specialmapping = {
else
editor:SetSelBackground(0,wx.wxWHITE)
end
if (style.alpha and ide.wxver >= "2.9.5") then
editor:SetSelAlpha(style.alpha)
end
-- set alpha for additional selecton: 0 - transparent, 255 - opaque
if ide.wxver >= "2.9.5" then editor:SetAdditionalSelAlpha(127) end
end,
seladd = function(editor,style)
if ide.wxver >= "2.9.5" then
if (style.fg) then
editor:SetAdditionalSelForeground(wx.wxColour(unpack(style.fg)))
end
if (style.bg) then
editor:SetAdditionalSelBackground(wx.wxColour(unpack(style.bg)))
end
if (style.alpha) then
editor:SetAdditionalSelAlpha(style.alpha)
end
end
end,
caret = function(editor,style)
if (style.fg) then
editor:SetCaretForeground(wx.wxColour(unpack(style.fg)))
@@ -126,6 +159,9 @@ local specialmapping = {
if (style.bg) then
editor:SetCaretLineBackground(wx.wxColour(unpack(style.bg)))
end
if (style.alpha and ide.wxver >= "2.9.5") then
editor:SetCaretLineBackAlpha(style.alpha)
end
end,
whitespace = function(editor,style)
@@ -141,15 +177,10 @@ local specialmapping = {
end
end,
calltipbg = function(editor,style)
if (style.bg) then
editor:CallTipSetBackground(wx.wxColour(unpack(style.bg)))
end
end,
fold = function(editor,style)
local clrfg = style.fg and wx.wxColour(unpack(style.fg))
local clrbg = style.bg and wx.wxColour(unpack(style.bg))
local clrhi = style.hi and wx.wxColour(unpack(style.hi))
local clrsel = style.sel and wx.wxColour(unpack(style.sel))
-- if selected background is set then enable support for it
@@ -178,6 +209,17 @@ local specialmapping = {
editor:SetFoldMarginColour(true, clrbg)
editor:SetFoldMarginHiColour(true, clrbg)
end
if clrhi then
editor:SetFoldMarginHiColour(true, clrhi)
end
end,
edge = function(editor,style)
if style.fg or style.col or style.mode then
editor:SetEdgeColour(wx.wxColour(unpack(style.fg or {220, 220, 220})))
editor:SetEdgeMode(style.mode or wxstc.wxSTC_EDGE_LINE)
editor:SetEdgeColumn(style.col or 80)
end
end,
marker = function(editor,markers)
@@ -189,6 +231,30 @@ local specialmapping = {
editor:MarkerDefine(id, ch, fg, bg)
end
end,
auxwindow = function(editor,style)
if not style then return end
local default = wxstc.wxSTC_STYLE_DEFAULT
local bg = style.bg and wx.wxColour(unpack(style.bg)) or editor:StyleGetBackground(default)
local fg = style.fg and wx.wxColour(unpack(style.fg)) or editor:StyleGetForeground(default)
local uimgr = ide.frame.uimgr
local panes = uimgr:GetAllPanes()
for index = 0, panes:GetCount()-1 do
local wind = uimgr:GetPane(panes:Item(index).name).window
local children = wind:GetChildren()
for child = 0, children:GetCount()-1 do
local data = children:Item(child):GetData()
local _, window = pcall(function() return data:DynamicCast("wxWindow") end)
if window then
window:SetBackgroundColour(bg)
window:SetForegroundColour(fg)
window:Refresh()
end
end
end
end,
}
local defaultmapping = {
@@ -262,6 +328,13 @@ function StylesApplyToEditor(styles,editor,font,fontitalic,lexerconvert)
end
end
-- additional selection (seladd) attributes can only be set after
-- normal selection (sel) attributes are set, so handle them again
if styles.seladd then specialmapping.seladd(editor, styles.seladd) end
-- calltip has a special style that needs to be enabled
if styles.calltip then editor:CallTipUseStyle(2) end
do
local defaultfg = styles.text and styles.text.fg or {127,127,127}
local indic = styles.indicator or {}
@@ -289,19 +362,17 @@ function ReApplySpecAndStyles()
-- these styles need to be updated as they are based on comment styles
if MarkupAddStyles then MarkupAddStyles(ide.config.styles) end
local errorlog = ide.frame.bottomnotebook.errorlog
local shellbox = ide.frame.bottomnotebook.shellbox
SetupKeywords(shellbox,"lua",nil,ide.config.stylesoutshell,ide.font.oNormal,ide.font.oItalic)
StylesApplyToEditor(ide.config.stylesoutshell,errorlog,ide.font.oNormal,ide.font.oItalic)
local openDocuments = ide.openDocuments
for i,doc in pairs(openDocuments) do
if (doc.editor.spec) then
SetupKeywords(doc.editor,nil,doc.editor.spec)
end
end
local errorlog = ide.frame.bottomnotebook.errorlog
local shellbox = ide.frame.bottomnotebook.shellbox
SetupKeywords(shellbox,"lua",nil,ide.config.stylesoutshell,ide.font.oNormal,ide.font.oItalic)
StylesApplyToEditor(ide.config.stylesoutshell,errorlog,ide.font.oNormal,ide.font.oItalic)
end
function ApplyStyleConfig(config, style)

View File

@@ -6,6 +6,7 @@
local iswindows = os.getenv('WINDIR') or (os.getenv('OS') or ''):match('[Ww]indows')
local islinux = not iswindows and not os.getenv('DYLD_LIBRARY_PATH') and io.open("/proc")
local arch = "x86" -- use 32bit by default
local unpack = table.unpack or unpack
if islinux then
local file = io.popen("uname -m")
@@ -72,6 +73,7 @@ ide = {
strategy = 2,
width = 60,
},
arg = {}, -- command line arguments
activateoutput = false, -- activate output/console on Run/Debug/Compile
unhidewindow = false, -- to unhide a gui window
@@ -134,6 +136,8 @@ ide = {
osname = wx.wxPlatformInfo.Get():GetOperatingSystemFamilyName(),
osarch = arch,
oshome = os.getenv("HOME") or (iswindows and os.getenv('HOMEDRIVE') and os.getenv('HOMEPATH')
and (os.getenv('HOMEDRIVE')..os.getenv('HOMEPATH'))),
wxver = string.match(wx.wxVERSION_STRING, "[%d%.]+"),
}
@@ -167,6 +171,8 @@ if not setfenv then -- Lua 5.2
return f end
end
dofile "src/version.lua"
for _, file in ipairs({"ids", "style", "keymap", "proto"}) do
dofile("src/editor/"..file..".lua")
end
@@ -177,15 +183,21 @@ ide.config.stylesoutshell = StylesGetDefault()
local function setLuaPaths(mainpath, osname)
-- use LUA_DEV to setup paths for Lua for Windows modules if installed
local luadev = osname == "Windows" and os.getenv('LUA_DEV')
local luadev_path = (luadev and wx.wxDirExists(luadev)
if luadev and not wx.wxDirExists(luadev) then luadev = nil end
local luadev_path = (luadev
and ('LUA_DEV/?.lua;LUA_DEV/?/init.lua;LUA_DEV/lua/?.lua;LUA_DEV/lua/?/init.lua')
:gsub('LUA_DEV', (luadev:gsub('[\\/]$','')))
or "")
local luadev_cpath = (luadev and wx.wxDirExists(luadev)
local luadev_cpath = (luadev
and ('LUA_DEV/?.dll;LUA_DEV/?51.dll;LUA_DEV/clibs/?.dll;LUA_DEV/clibs/?51.dll')
:gsub('LUA_DEV', (luadev:gsub('[\\/]$','')))
or "")
if luadev then
local path, clibs = os.getenv('PATH'), luadev:gsub('[\\/]$','')..'\\clibs'
if not path:find(clibs, 1, true) then wx.wxSetEnv('PATH', path..';'..clibs) end
end
-- (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.
@@ -205,6 +217,7 @@ local function setLuaPaths(mainpath, osname)
nil
if clibs then wx.wxSetEnv("LUA_CPATH",
package.cpath .. ';' .. clibs .. ';' .. luadev_cpath) end
ide.osclibs = clibs -- keep the list to use for other Lua versions
end
---------------
@@ -250,7 +263,9 @@ ide.app = dofile(ide.config.path.app.."/app.lua")
local app = assert(ide.app)
local function loadToTab(filter, folder, tab, recursive, proto)
filter = filter and type(filter) ~= 'function' and app.loadfilters[filter] or nil
if filter and type(filter) ~= 'function' then
filter = app.loadfilters[filter] or nil
end
for _, file in ipairs(FileSysGetRecursive(folder, recursive, "*.lua")) do
if not filter or filter(file) then
LoadLuaFileExt(tab, file, proto)
@@ -271,8 +286,30 @@ end
-- load packages
local function loadPackages(filter)
loadToTab(filter, "packages", ide.packages, false, ide.proto.Plugin)
-- assign file names to each package
for fname, package in pairs(ide.packages) do package.fname = fname end
if ide.oshome then
local userpackages = MergeFullPath(ide.oshome, ".zbstudio/packages")
loadToTab(filter, userpackages, ide.packages, false, ide.proto.Plugin)
end
-- check dependencies and assign file names to each package
local unload = {}
for fname, package in pairs(ide.packages) do
local needsversion = tonumber(package.dependencies)
or type(package.dependencies) == 'table' and tonumber(package.dependencies[1])
or -1
local isversion = tonumber(ide.VERSION)
if isversion and needsversion > isversion then
(DisplayOutputLn or print)(
("Package '%s' not loaded: requires version %s, but you are running version %s")
:format(fname, needsversion, ide.VERSION)
)
table.insert(unload, fname)
end
package.fname = fname
end
-- remove packages that need to be unloaded
for _, fname in ipairs(unload) do ide.packages[fname] = nil end
end
function UpdateSpecs()
@@ -319,35 +356,6 @@ local resumePrint do
end
end
-----------------------
-- load config
local function addConfig(filename,isstring)
if not filename then return end
-- skip those files that don't exist
if not isstring and not wx.wxFileName(filename):FileExists() then return end
-- if it's marked as command, but exists as a file, load it as a file
if isstring and wx.wxFileName(filename):FileExists() then isstring = false end
local cfgfn, err, msg
if isstring
then msg, cfgfn, err = "string", loadstring(filename)
else msg, cfgfn, err = "file", loadfile(filename) end
if not cfgfn then
print(("Error while loading configuration %s: '%s'."):format(msg, err))
else
ide.config.os = os
ide.config.wxstc = wxstc
ide.config.load = { interpreters = loadInterpreters,
specs = loadSpecs, tools = loadTools }
setfenv(cfgfn,ide.config)
local _, err = pcall(function()cfgfn(assert(_G or _ENV))end)
if err then
print(("Error while processing configuration %s: '%s'."):format(msg, err))
end
end
end
function GetIDEString(keyword, default)
return app.stringtable[keyword] or default or keyword
end
@@ -355,7 +363,13 @@ end
----------------------
-- process config
addConfig(ide.config.path.app.."/config.lua")
-- set ide.config environment
ide.config.os = os
ide.config.wxstc = wxstc
ide.config.load = { interpreters = loadInterpreters, specs = loadSpecs,
tools = loadTools }
LoadLuaConfig(ide.config.path.app.."/config.lua")
ide.editorApp:SetAppName(GetIDEString("settingsapp"))
@@ -383,18 +397,17 @@ loadSpecs()
loadTools()
do
local home = os.getenv("HOME") or (iswindows and (os.getenv('HOMEDRIVE')..os.getenv('HOMEPATH')))
ide.configs = {
system = MergeFullPath("cfg", "user.lua"),
user = home and MergeFullPath(home, ".zbstudio/user.lua"),
user = ide.oshome and MergeFullPath(ide.oshome, ".zbstudio/user.lua"),
}
-- process configs
addConfig(ide.configs.system)
addConfig(ide.configs.user)
LoadLuaConfig(ide.configs.system)
LoadLuaConfig(ide.configs.user)
-- process all other configs (if any)
for _, v in ipairs(configs) do addConfig(v, true) end
for _, v in ipairs(configs) do LoadLuaConfig(v, true) end
configs = nil
local sep = GetPathSeparator()
@@ -418,8 +431,6 @@ for _, file in ipairs({
dofile("src/editor/"..file..".lua")
end
dofile "src/version.lua"
-- register all the plugins
PackageEventHandle("onRegister")
@@ -427,12 +438,12 @@ PackageEventHandle("onRegister")
SettingsRestoreEditorSettings()
SettingsRestoreFramePosition(ide.frame, "MainFrame")
SettingsRestoreFileHistory(SetFileHistory)
SettingsRestoreProjectSession(FileTreeSetProjects)
SettingsRestoreFileSession(function(tabs, params)
if params and params.recovery
then return SetOpenTabs(params)
else return SetOpenFiles(tabs, params) end
end)
SettingsRestoreProjectSession(FileTreeSetProjects)
SettingsRestoreView()
-- ---------------------------------------------------------------------------
@@ -457,6 +468,11 @@ end
if app.postinit then app.postinit() end
if ide.osname == 'Macintosh' then
ide.frame:SetAcceleratorTable(wx.wxAcceleratorTable({
wx.wxAcceleratorEntry(wx.wxACCEL_CTRL, ('M'):byte(), ID_VIEWMINIMIZE)
}))
end
-- only set menu bar *after* postinit handler as it may include adding
-- app-specific menus (Help/About), which are not recognized by MacOS
-- as special items unless SetMenuBar is done after menus are populated.

View File

@@ -162,7 +162,7 @@ end
function FileSysGetRecursive(path, recursive, spec, skip)
spec = spec or "*"
local content = {}
local sep = string.char(wx.wxFileName.GetPathSeparator())
local sep = GetPathSeparator()
-- recursion is done in all folders but only those folders that match
-- the spec are returned. This is the pattern that matches the spec.
@@ -172,12 +172,16 @@ function FileSysGetRecursive(path, recursive, spec, skip)
local dir = wx.wxDir(path)
if not dir:IsOpened() then return end
local found, file = dir:GetFirst("*", wx.wxDIR_DIRS + wx.wxDIR_NO_FOLLOW)
local found, file = dir:GetFirst("*", wx.wxDIR_DIRS)
while found do
if not skip or not file:find(skip) then
local fname = wx.wxFileName(path, file):GetFullPath()
if fname:find(specmask) then table.insert(content, fname..sep) end
if recursive then getDir(fname, spec) end
-- check if this name already appears in the path earlier;
-- Skip the processing if it does as it could lead to infinite
-- recursion with circular references created by symlinks.
if recursive and select(2, fname:gsub(file..sep,'')) <= 2 then
getDir(fname, spec) end
end
found, file = dir:GetNext()
end
@@ -206,12 +210,13 @@ function FileSysGetRecursive(path, recursive, spec, skip)
return content
end
local normalflags = wx.wxPATH_NORM_ABSOLUTE + wx.wxPATH_NORM_DOTS + wx.wxPATH_NORM_TILDE
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)
return (file:Normalize(normalflags, p)
and file:FileExists()
and file:GetFullPath()
or nil)
@@ -222,13 +227,19 @@ function MergeFullPath(p, f)
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)
return (file:Normalize(normalflags, p)
and file:GetFullPath()
or nil)
end
function FileWrite(file, content)
local log = wx.wxLogNull() -- disable error reporting; will report as needed
if not wx.wxFileExists(file)
and not wx.wxFileName(file):Mkdir(tonumber(755,8), wx.wxPATH_MKDIR_FULL) then
return nil, wx.wxSysErrorMsg()
end
local file = wx.wxFile(file, wx.wxFile.write)
if not file:IsOpened() then return nil, wx.wxSysErrorMsg() end
@@ -250,11 +261,14 @@ function FileRead(file)
return content, wx.wxSysErrorMsg()
end
function FileRename(file1, file2) return wx.wxRenameFile(file1, file2) end
function FileRename(file1, file2)
local log = wx.wxLogNull() -- disable error reporting; will report as needed
return wx.wxRenameFile(file1, file2), wx.wxSysErrorMsg()
end
function FileCopy(file1, file2)
local log = wx.wxLogNull() -- disable error reporting; will report as needed
return wx.wxCopyFile(file1, file2)
return wx.wxCopyFile(file1, file2), wx.wxSysErrorMsg()
end
TimeGet = pcall(require, "socket") and socket.gettime or os.clock
@@ -279,7 +293,7 @@ function FixUTF8(s, repl)
local p, len, invalid = 1, #s, {}
while p <= len do
if p == s:find("[%z\1-\127]", p) then p = p + 1
elseif p == s:find("[\194-\223][\123-\191]", p) then p = p + 2
elseif p == s:find("[\194-\223][\128-\191]", p) then p = p + 2
elseif p == s:find( "\224[\160-\191][\128-\191]", p)
or p == s:find("[\225-\236][\128-\191][\128-\191]", p)
or p == s:find( "\237[\128-\159][\128-\191]", p)
@@ -307,6 +321,7 @@ function RequestAttention()
local cmd = [[osascript -e 'tell application "%s" to activate']]
wx.wxExecute(cmd:format(ide.editorApp:GetAppName()), wx.wxEXEC_ASYNC)
elseif ide.osname == "Windows" then
if frame:IsIconized() then frame:Iconize(false) end
frame:Raise() -- raise the window
local winapi = require 'winapi'
@@ -320,7 +335,9 @@ function RequestAttention()
-- found the window, now need to activate it:
-- send some input to the window and then
-- bring our window to foreground (doesn't work without some input)
winapi.send_to_window(0x1B)
-- send Attn key twice (down and up)
winapi.send_to_window(0xF6, false)
winapi.send_to_window(0xF6, true)
for _, w in ipairs(wins) do w:set_foreground() end
end
end
@@ -364,8 +381,9 @@ end
function LoadLuaFileExt(tab, file, proto)
local cfgfn,err = loadfile(file)
local report = DisplayOutputLn or print
if not cfgfn then
print(("Error while loading file: '%s'."):format(err))
report(("Error while loading file: '%s'."):format(err))
else
local name = file:match("([a-zA-Z_0-9%-]+)%.lua$")
if not name then return end
@@ -379,7 +397,7 @@ function LoadLuaFileExt(tab, file, proto)
local success, result = pcall(function()return cfgfn(assert(_G or _ENV))end)
if not success then
print(("Error while processing file: '%s'."):format(result))
report(("Error while processing file: '%s'."):format(result))
else
if (tab[name]) then
local out = tab[name]
@@ -393,6 +411,30 @@ function LoadLuaFileExt(tab, file, proto)
end
end
function LoadLuaConfig(filename,isstring)
if not filename then return end
-- skip those files that don't exist
if not isstring and not wx.wxFileName(filename):FileExists() then return end
-- if it's marked as command, but exists as a file, load it as a file
if isstring and wx.wxFileName(filename):FileExists() then isstring = false end
local cfgfn, err, msg
if isstring
then msg, cfgfn, err = "string", loadstring(filename)
else msg, cfgfn, err = "file", loadfile(filename) end
local report = DisplayOutputLn or print
if not cfgfn then
report(("Error while loading configuration %s: '%s'."):format(msg, err))
else
setfenv(cfgfn,ide.config)
local _, err = pcall(function()cfgfn(assert(_G or _ENV))end)
if err then
report(("Error while processing configuration %s: '%s'."):format(msg, err))
end
end
end
function LoadSafe(data)
local f, res = loadstring(data)
if not f then return f, res end
@@ -407,3 +449,5 @@ function LoadSafe(data)
debug.sethook()
return ok, res
end
function EscapeMagic(s) return s:gsub('([%(%)%.%%%+%-%*%?%[%^%$%]])','%%%1') end

View File

@@ -43,6 +43,15 @@ editor:AddText([[
ok(limit(10000, function() EditorAutoComplete(editor) end),
"Auto-complete doesn't loop for table index reference 2/2.")
editor:SetText('')
editor:AddText([[
local a = ...
local b = a.b
local c = b.]])
ok(limit(10000, function() EditorAutoComplete(editor) end),
"Auto-complete doesn't loop for classes that reference '...'.")
local interpreter = ide:GetInterpreter():GetFileName()
ProjectSetInterpreter("gideros")

View File

@@ -13,6 +13,36 @@ editor.CallTipShow = CTS
ok(value:find("print") and not value:find("select"),
"Tooltip ignores values in strings.")
local api = {
t = {
childs = {
func = {
args = "(args)",
description = [[Description Line1
Line2
Line4
Line5
Line7]],
returns = "(returns)",
type = "function"
}
}
}
}
ide:AddAPI("lua", "test", api)
table.insert(ide.interpreter.api, "test")
ReloadLuaAPI()
local tooltip = GetTipInfo(editor, "t.func(")
ok(tooltip:find("Line1\nLine2"), "Newlines are shown as newlines in tooltip")
ok(tooltip:find("Line2\n\nLine4"), "Empty lines are shown as empty lines in tooltip")
ok(tooltip:find("Line4\n\tLine5"), "Newlines with indentation are shown as lines with indentation in tooltip")
ok(tooltip:find("Line5\n\t\n\tLine7"), "Empty lines with indentation are shown in tooltip")
ide:RemoveAPI("lua", "test")
ReloadLuaAPI()
-- cleanup
ide:GetDocument(editor).isModified = false
ClosePage()

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