Compare commits
442 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b0ce69da6a | ||
|
|
da7edc4580 | ||
|
|
31b7e4d788 | ||
|
|
c940b56459 | ||
|
|
dcc28d9ce2 | ||
|
|
334a071219 | ||
|
|
48ba4e26b8 | ||
|
|
8da70c6e75 | ||
|
|
61198caae5 | ||
|
|
4e8b9d41ba | ||
|
|
86af637781 | ||
|
|
08825ba79a | ||
|
|
f2b3161474 | ||
|
|
22f2f68a3a | ||
|
|
e3f666570a | ||
|
|
dc757d48e5 | ||
|
|
da6b7db0e6 | ||
|
|
ec218e1424 | ||
|
|
c178ec9ab4 | ||
|
|
9f87a780a7 | ||
|
|
40809b6396 | ||
|
|
6f04ef8921 | ||
|
|
a3235b23bb | ||
|
|
b3fdde036e | ||
|
|
1e86c3c2d6 | ||
|
|
57a89f0c45 | ||
|
|
710c49850c | ||
|
|
94662bbd4c | ||
|
|
fc1f9375ed | ||
|
|
7db6b1ad07 | ||
|
|
d70d6a0bd6 | ||
|
|
b130e68b51 | ||
|
|
fdbb835199 | ||
|
|
3cc2d861db | ||
|
|
e5ca96879a | ||
|
|
80248d2a77 | ||
|
|
400de47586 | ||
|
|
cfdbbff3c7 | ||
|
|
5235cc001b | ||
|
|
12fd9611f7 | ||
|
|
be323d555d | ||
|
|
11facf0acb | ||
|
|
4b13017620 | ||
|
|
7ddaaa20e6 | ||
|
|
b659dfaf79 | ||
|
|
20c73a9e92 | ||
|
|
dfca13b96d | ||
|
|
3c25189fdb | ||
|
|
a1c67447b5 | ||
|
|
6710758962 | ||
|
|
e761a5f7ef | ||
|
|
c8f84e4694 | ||
|
|
e40215a4d1 | ||
|
|
46d6ab8f9e | ||
|
|
377fbfab39 | ||
|
|
4c4259f5ca | ||
|
|
0e8b29936e | ||
|
|
54f16def09 | ||
|
|
e8d7235cfb | ||
|
|
bac1cbc028 | ||
|
|
94ceb8d9df | ||
|
|
6f1a0c0316 | ||
|
|
a225d7e7c7 | ||
|
|
e3f7719ca7 | ||
|
|
809e46eaf7 | ||
|
|
5450ad8311 | ||
|
|
68866eb2cb | ||
|
|
9ff569e8ce | ||
|
|
9375235fc6 | ||
|
|
a2cd63afa6 | ||
|
|
6052a86f0a | ||
|
|
75357d7f41 | ||
|
|
c493f62466 | ||
|
|
89ef72aab3 | ||
|
|
343423898e | ||
|
|
cf02a3ea55 | ||
|
|
811f2a7021 | ||
|
|
fe92bf89e5 | ||
|
|
c9ac9ca23f | ||
|
|
300c6b61c6 | ||
|
|
8678404b84 | ||
|
|
54b29472cc | ||
|
|
f0a3305753 | ||
|
|
d9ce3d0538 | ||
|
|
b457ccbccd | ||
|
|
1fb61028b1 | ||
|
|
98fc8e05bc | ||
|
|
03989f3fd8 | ||
|
|
b41eb364bb | ||
|
|
27708b4dd2 | ||
|
|
0d2ab45c6b | ||
|
|
0cfede0e7a | ||
|
|
2a404541e5 | ||
|
|
657526eab4 | ||
|
|
eb16a80515 | ||
|
|
e283bcb65d | ||
|
|
a1459ba494 | ||
|
|
042998dd71 | ||
|
|
717d46a332 | ||
|
|
b6fd404788 | ||
|
|
02a43a63a6 | ||
|
|
719b76ea80 | ||
|
|
eae8540708 | ||
|
|
539a74aa7a | ||
|
|
4b0bcaa20e | ||
|
|
486577524b | ||
|
|
c4567e769c | ||
|
|
7d956357c5 | ||
|
|
600a379622 | ||
|
|
afbe8cb307 | ||
|
|
9d1cba52ba | ||
|
|
3d29b5f188 | ||
|
|
38948cd2b6 | ||
|
|
d79035bf7a | ||
|
|
1fb919a6e6 | ||
|
|
227631f1df | ||
|
|
1006f7b165 | ||
|
|
44dc63dbad | ||
|
|
adc2532802 | ||
|
|
3937a134d5 | ||
|
|
f7329fb234 | ||
|
|
0775e1bcdc | ||
|
|
b0eabd6382 | ||
|
|
6955e1b3f4 | ||
|
|
3c4fc71249 | ||
|
|
a2dc2e9934 | ||
|
|
5b026e10a6 | ||
|
|
131fc63deb | ||
|
|
9ea833ce7d | ||
|
|
070111b06e | ||
|
|
a315b1a87b | ||
|
|
8e2257f8ac | ||
|
|
0c227c0ad6 | ||
|
|
0555fed7ad | ||
|
|
d3d6a7a485 | ||
|
|
58f86894e9 | ||
|
|
51c0443c9a | ||
|
|
ae6f7c5589 | ||
|
|
f5dc6f5018 | ||
|
|
c3c141fedf | ||
|
|
fcb7d2a2ad | ||
|
|
83b69ad8e8 | ||
|
|
a6db07d8e1 | ||
|
|
44f8d42156 | ||
|
|
b9a1bf27ac | ||
|
|
1a673ba7e5 | ||
|
|
c21746f1a7 | ||
|
|
41c38d0bcb | ||
|
|
a5cd585bcc | ||
|
|
c2c631c03e | ||
|
|
285a599dc9 | ||
|
|
f9903f3470 | ||
|
|
843a22e6e9 | ||
|
|
b90305efff | ||
|
|
64a9f7c701 | ||
|
|
64a68b443b | ||
|
|
8460abef86 | ||
|
|
63f76b6695 | ||
|
|
7d2884ebfe | ||
|
|
4efc725211 | ||
|
|
4d44f28a06 | ||
|
|
804567f6c3 | ||
|
|
b811a8dd39 | ||
|
|
638bc477d7 | ||
|
|
aa0ecdb4f4 | ||
|
|
dc1990c7b9 | ||
|
|
2e497bf831 | ||
|
|
e087186def | ||
|
|
715b7d06c4 | ||
|
|
d68da68c4b | ||
|
|
83088fe798 | ||
|
|
1d9a043c25 | ||
|
|
d67fcf931e | ||
|
|
379db00a5c | ||
|
|
d65acb2d40 | ||
|
|
c7041940f3 | ||
|
|
f7df30614d | ||
|
|
5db556849b | ||
|
|
471eaa9087 | ||
|
|
e54ee64d79 | ||
|
|
45c83f73db | ||
|
|
0ffd472396 | ||
|
|
adaca47bf6 | ||
|
|
d2d477b8f5 | ||
|
|
3cfc5f65c2 | ||
|
|
1ce791700c | ||
|
|
c28ef5000a | ||
|
|
61bb92950a | ||
|
|
b14198161e | ||
|
|
ad2dd2e40e | ||
|
|
d9fdbe0745 | ||
|
|
905d9cd75d | ||
|
|
d68b84f862 | ||
|
|
1e7f5de4db | ||
|
|
87d116a1c3 | ||
|
|
33b4641b63 | ||
|
|
9efb4454e4 | ||
|
|
02f7e24d33 | ||
|
|
e001386383 | ||
|
|
9257c03b07 | ||
|
|
6216ac37a2 | ||
|
|
476aa9d90a | ||
|
|
c665a0cc5c | ||
|
|
96397e66c5 | ||
|
|
758c5a8187 | ||
|
|
52e02f087c | ||
|
|
a02437dee1 | ||
|
|
3cd754b6b9 | ||
|
|
9a8f870ae4 | ||
|
|
ea5b78707d | ||
|
|
1d8b02bb41 | ||
|
|
83f52d0a57 | ||
|
|
d807accec2 | ||
|
|
430469ab3a | ||
|
|
e8978d8e89 | ||
|
|
aa0a0f8520 | ||
|
|
c089037e26 | ||
|
|
cf67ab3b6a | ||
|
|
5beccc0498 | ||
|
|
1e0e286682 | ||
|
|
b895f51beb | ||
|
|
4e5356670b | ||
|
|
7cbf2f99f6 | ||
|
|
84d7928b94 | ||
|
|
37b73d6c49 | ||
|
|
f1b74b9c2f | ||
|
|
9449650d47 | ||
|
|
b3bc39a8d5 | ||
|
|
ab4ae3e281 | ||
|
|
18dadbc001 | ||
|
|
b4f0635ab7 | ||
|
|
9a4ed47179 | ||
|
|
c314996902 | ||
|
|
3a49e4c37d | ||
|
|
23a874b5ae | ||
|
|
92b88a8d26 | ||
|
|
3a8cb8aa42 | ||
|
|
08d1d9f1f8 | ||
|
|
95fcf4aa79 | ||
|
|
9c47414635 | ||
|
|
8969abb43f | ||
|
|
ce933f4f81 | ||
|
|
b8de606bed | ||
|
|
9c60c1e37c | ||
|
|
e9a8a8bd9c | ||
|
|
a91426eb5c | ||
|
|
ab5bec082d | ||
|
|
e384146089 | ||
|
|
a5df5d63b6 | ||
|
|
11729813a6 | ||
|
|
e577d96a4e | ||
|
|
d61be1cf77 | ||
|
|
6698f43f76 | ||
|
|
51cd41ceba | ||
|
|
0480e9ca39 | ||
|
|
b67c509f30 | ||
|
|
168d65b411 | ||
|
|
a667b75177 | ||
|
|
91a8518db9 | ||
|
|
eb68425a25 | ||
|
|
eaa9aba068 | ||
|
|
95452706a0 | ||
|
|
a5eaa2fd8a | ||
|
|
445d90f50d | ||
|
|
36b8a414d5 | ||
|
|
21d0991b9b | ||
|
|
483c70bef2 | ||
|
|
1613675b31 | ||
|
|
2cea675c10 | ||
|
|
2723801604 | ||
|
|
fa6e8d1442 | ||
|
|
037476ac49 | ||
|
|
a457ed62b9 | ||
|
|
ae3ddb59f7 | ||
|
|
78c44e6060 | ||
|
|
9284a24750 | ||
|
|
c8df92f8a0 | ||
|
|
1ae6ffe7f7 | ||
|
|
ae561ff880 | ||
|
|
da584b9e0a | ||
|
|
809ba33187 | ||
|
|
844626c6f4 | ||
|
|
b498140958 | ||
|
|
68ccda4ef5 | ||
|
|
5632913e40 | ||
|
|
7496040f34 | ||
|
|
2b7f0f4ad6 | ||
|
|
f323cc967b | ||
|
|
9cd361989c | ||
|
|
c5df05f03e | ||
|
|
3709f61fc4 | ||
|
|
59caf6cae5 | ||
|
|
44df223ac5 | ||
|
|
2dd3209682 | ||
|
|
0c52cde070 | ||
|
|
b734637eb5 | ||
|
|
4c01a530a0 | ||
|
|
8d965cca32 | ||
|
|
01eab250eb | ||
|
|
6b9adf1527 | ||
|
|
68a8fcec47 | ||
|
|
13f1174bb7 | ||
|
|
d370279d24 | ||
|
|
1bbefcbf7b | ||
|
|
dd3ce4d1e7 | ||
|
|
fdc17f1579 | ||
|
|
02bbdf17f8 | ||
|
|
8492df40de | ||
|
|
8b9197552c | ||
|
|
377a4861ee | ||
|
|
241a5d13c3 | ||
|
|
344ed6fd80 | ||
|
|
bd03b4c4d1 | ||
|
|
4ba03afa8c | ||
|
|
cb6971e37d | ||
|
|
9c3b35d8fe | ||
|
|
82f62d4d7d | ||
|
|
38c56c4d31 | ||
|
|
683218a909 | ||
|
|
d68e7ff7ce | ||
|
|
c4c3e7e51e | ||
|
|
2460a82153 | ||
|
|
23a8d495f5 | ||
|
|
2ccd542610 | ||
|
|
1c66dc733f | ||
|
|
5934b9733d | ||
|
|
7ae28cc479 | ||
|
|
add8342f67 | ||
|
|
b89bb73476 | ||
|
|
a00fa953c2 | ||
|
|
1e623b1d65 | ||
|
|
c0ddad642f | ||
|
|
4f1286612b | ||
|
|
267e631933 | ||
|
|
0da23d376d | ||
|
|
bdbfd3d71a | ||
|
|
11edc26279 | ||
|
|
4171d1ce3b | ||
|
|
bc866f8375 | ||
|
|
42f0bae28f | ||
|
|
d0c712950f | ||
|
|
228b724f5b | ||
|
|
5fac7e15a8 | ||
|
|
1338204787 | ||
|
|
afcbcfb522 | ||
|
|
64a24768cd | ||
|
|
39c4cd6800 | ||
|
|
c854c97c22 | ||
|
|
35a5313e77 | ||
|
|
2525736bea | ||
|
|
102d470380 | ||
|
|
9ade820252 | ||
|
|
c2d6e7bed8 | ||
|
|
8a51d2512e | ||
|
|
542de89d16 | ||
|
|
6aafdf9a84 | ||
|
|
c9b82f55b6 | ||
|
|
0497ef686a | ||
|
|
476df369ba | ||
|
|
5c14fc1025 | ||
|
|
92da4732c7 | ||
|
|
c9c01ec769 | ||
|
|
ebb6a8525e | ||
|
|
4edbe7b491 | ||
|
|
a21c39e5c8 | ||
|
|
74a39850f2 | ||
|
|
c821336adf | ||
|
|
e36e455e1b | ||
|
|
7f675b34ad | ||
|
|
33ab4a1196 | ||
|
|
6cc90c2bd3 | ||
|
|
9ef4438b4f | ||
|
|
d19db6e50d | ||
|
|
93cfc76d78 | ||
|
|
e3ab970d5a | ||
|
|
7f00380fe1 | ||
|
|
f95a48212e | ||
|
|
033c781467 | ||
|
|
3be3f700f4 | ||
|
|
109972a5e7 | ||
|
|
a7cb89eda1 | ||
|
|
7cbef66b7d | ||
|
|
d15837a69e | ||
|
|
2690f3deea | ||
|
|
82517bc57e | ||
|
|
f74653aba3 | ||
|
|
879ab8f506 | ||
|
|
9b899b14b4 | ||
|
|
bf1d5c617e | ||
|
|
728beae0b2 | ||
|
|
ebe433a65a | ||
|
|
6d8c2650aa | ||
|
|
0f51d31daa | ||
|
|
0288253929 | ||
|
|
777690862d | ||
|
|
10828dce8b | ||
|
|
62df942569 | ||
|
|
059e093cb3 | ||
|
|
736c30a6bc | ||
|
|
c60770b2f5 | ||
|
|
fc4611e1fa | ||
|
|
01c6eeb782 | ||
|
|
cfb0b2f6bb | ||
|
|
24fe65848b | ||
|
|
5f2a6b1382 | ||
|
|
9f7b6c47ab | ||
|
|
1511c4c820 | ||
|
|
7c33e7bf55 | ||
|
|
570743a3da | ||
|
|
62833599f4 | ||
|
|
36f11ee2bd | ||
|
|
2580ce36a8 | ||
|
|
8a4c3693f2 | ||
|
|
d2cb1690cb | ||
|
|
c7b03095c4 | ||
|
|
92b02bbe0e | ||
|
|
f8ab060457 | ||
|
|
3fe98ed092 | ||
|
|
87fa5d1302 | ||
|
|
09b81d2796 | ||
|
|
2d9683675b | ||
|
|
d524f06429 | ||
|
|
8dfb5db642 | ||
|
|
cfc00e6c6b | ||
|
|
17522a2b16 | ||
|
|
902f40202a | ||
|
|
34d25acb74 | ||
|
|
b65757584b | ||
|
|
518c2ca90a | ||
|
|
005eb4b52c | ||
|
|
daa06ac8de | ||
|
|
fdd1a9acdb | ||
|
|
f42c69b158 | ||
|
|
991edfdac3 | ||
|
|
64552d2733 | ||
|
|
a7819bd022 | ||
|
|
529e8b910f | ||
|
|
e886befe4c | ||
|
|
df1583b9c2 | ||
|
|
cabc579b4b | ||
|
|
c82d9d4f1b | ||
|
|
3bb2926c88 |
504
CHANGELOG.md
504
CHANGELOG.md
@@ -1,5 +1,509 @@
|
||||
# ZeroBrane Studio Changelog
|
||||
|
||||
## v0.80 (Aug 31 2014)
|
||||
|
||||
### Highlights
|
||||
- Added support for expanding table elements in Watch window.
|
||||
- Added editing of values in Watch window.
|
||||
- Added highlighting all instances of selected text.
|
||||
- Added replacing all selected instances using a dialog.
|
||||
- Added saving (one-line) layout for editor tabs.
|
||||
- Added support for `filename:<line>` and `filename:p<pos>` on the command line.
|
||||
- Added search in Console and Output windows.
|
||||
- Improved compatibility with Lua 5.2 to run the IDE.
|
||||
|
||||
### Special thanks
|
||||
- To [Li Jia](https://github.com/tiwb) for fixing remote path map when 'runonstart' option is set.
|
||||
|
||||
### Improvements
|
||||
- Added default values for `hotexit` and `saveallonrun` settings.
|
||||
- Added debugger `GetHostName` and `GetPortNumber` methods (#166).
|
||||
- Added a check for a local shortcut (F2/Del) being enabled before triggering.
|
||||
- Added refresh of expanded Watch values.
|
||||
- Added support for expanding table elements in Watch window.
|
||||
- Added package `AddWatch` method (#166).
|
||||
- Added `toolbar.iconsize` to configure toolbar icon size.
|
||||
- Added `run-as-scratchpad` toolbar icon (hidden by default).
|
||||
- Added `run` toolbar icon (hidden by default).
|
||||
- Added `find-in-files` toolbar icon (hidden by default).
|
||||
- Added support for disabling individual icons in the toolbar.
|
||||
- Added replacing all selected instances using a dialog (closes #342).
|
||||
- Added highlighting all instances of selected text (closes #344).
|
||||
- Added `filetree.mousemove` option to disable drag-n-drop (closes #351).
|
||||
- Added `suspended` to Output panel title when debugger is stopped (closes #350).
|
||||
- Added a warning when remote console can't evaluate an expression (#350).
|
||||
- Added handling of `osname` to package dependencies (#166).
|
||||
- Added `onIdle` event (#166).
|
||||
- Added `tree:FindItem` method (#166).
|
||||
- Added package `Yield` method (#166).
|
||||
- Added ability to set location of `ini` file from config.
|
||||
- Added ability to load bitmap as toolbar icon.
|
||||
- Added package `RemoveMenuItem` method (#166).
|
||||
- Added ability to customize toolbar.
|
||||
- Added saving (one-line) layout for editor tabs.
|
||||
- Added centering of the screen after re-indenting and sorting (#337).
|
||||
- Added local to variable 'activated' in function mapRemotePath
|
||||
- Added centering of the screen after 'go to definition' and back (#337).
|
||||
- Added centering of the screen after selection from the function list (#337).
|
||||
- Added package `onEditorUpdateUI` event (#166).
|
||||
- Added package `AddPanel` method (#166).
|
||||
- Added package `GetUIManager` method (#166).
|
||||
- Added editor `SetupKeywords` method (#166).
|
||||
- Added document `GetFileExit` method (#166).
|
||||
- Added `onEditorPainted` event (#166).
|
||||
- Added support for `name:<line>` and `name:p<pos>` on the command line.
|
||||
- Added error reporting on failure to load file from the command line.
|
||||
- Added metalua components to MANIFEST (missing in packaging on OSX).
|
||||
- Added saving auto-recovery record on switching from the application.
|
||||
- Added `hotexit` option to exit without forcing to save files.
|
||||
- Added setting of margin properties to support their reordering.
|
||||
- Added error reporting on failure to delete directory from project tree.
|
||||
- Added check for shortcut in conflict being enabled before activating (#233).
|
||||
- Added workaround for missing `GetChildren` call in some wxlua configurations.
|
||||
- Added unfolding modified lines to avoid leaving hidden lines in the editor.
|
||||
- Added search in Console and Output windows (closes #313).
|
||||
- Allowed double-click selection in the Output window (#313).
|
||||
- Avoided system lib conflict when debugging by using bundled libs (fixes #355).
|
||||
- Disabled editing on non-root watch elements.
|
||||
- Disabled smart indentation for multi-line comments and strings (#324).
|
||||
- Disabled re-indentation of multi-line comments/strings (#324).
|
||||
- Disabled `Opt+Shift+Left/Right` shortcut as it conflicts with block selection.
|
||||
- Enabled editing of values in Watch window.
|
||||
- Enabled `editor.autoreload` by default.
|
||||
- Improved config handling when `editor` configuration is removed/empty.
|
||||
- Improved `autotabs` logic when the file starts with indentation.
|
||||
- Improved auto-complete logic that tracks variable assignments (fixes #343).
|
||||
- Improved cursor positioning after re-indenting or sorting.
|
||||
- Improved compatibility with Lua5.2 to run the IDE.
|
||||
- Increased default project history length to 20.
|
||||
- Removed check for multiple references in stack values.
|
||||
- Refactored stack processing to use methods to handle expandable table values.
|
||||
- Refactored file name generation for compilation and static analysis.
|
||||
- Removed erroneous message about failure to open '-psn...' file on OSX.
|
||||
- Renamed all image files to remove cruft from their names.
|
||||
- Simplified logic for watch processing.
|
||||
- Switched from using TreeItemData to Lua tables for watch expressions.
|
||||
- Switched to using tree control for watches.
|
||||
- Updated copas library to support non-blocking requests using socket.http.
|
||||
- Updated Stack and Watch views to better stringify keys.
|
||||
- Updated watch menu to handle item under mouse cursor.
|
||||
- Updated constants for image lists.
|
||||
- Updated `FindMenuItem` method to search in the main and specified menus (#166).
|
||||
- Updated `ide.config` to access wx, wxstc, and os through metatable.
|
||||
- Updated recent projects/files handling to allow menus to be removed.
|
||||
- Updated package `FindMenuItem` method (#166).
|
||||
- Updated `autotabs` to respect `usetabs` when no indentation is present.
|
||||
- Updated copy/cut to capture one instance when all are the same (closes #345).
|
||||
- Updated default marker colors for lighter border (#305).
|
||||
- Updated auto-recovery logic to skip missing files (fixes #323).
|
||||
|
||||
### Fixes
|
||||
- Fixed disabling auto-recovery on app switching.
|
||||
- Fixed find-in-files error when used with editor not in focus (fixes #354).
|
||||
- Fixed package `GetStack` method to return proper control (#166).
|
||||
- Fixed Watch window background color on some Mint Linux systems.
|
||||
- Fixed debugging error when `debugger.runonstart` is specified (fixes #348, #341).
|
||||
- Fixed keybinding for `Ctrl-<punctuation>` working on Linux (fixes #346).
|
||||
- Fixed localization based on static analysis.
|
||||
- Fixed remote path map when 'runonstart' option is set.
|
||||
- Fixed error reporting during Analyze (fixes #340).
|
||||
- Fixed using image lists for stack/filetree to keep them in memory.
|
||||
- Fixed indentation when Enter is hit at the middle of a line.
|
||||
- Fixed formatting of `until` statements (fixes #335).
|
||||
- Fixed formatting of strings including comments '--' (#335).
|
||||
- Fixed restoring proper file names for unsaved tabs during auto-recovery.
|
||||
- Fixed deleting 'dynamic words' when multiple lines are removed.
|
||||
- Fixed `love.update` description (#247).
|
||||
- Fixed indentation of strings starting from `endSomething` (#324).
|
||||
- Fixed use of '%' in replacement for Lua5.2 compatibility (#153, #156, #143).
|
||||
- Fixed warnings from static analysis.
|
||||
|
||||
## v0.70 (Jun 18 2014)
|
||||
|
||||
### Highlights
|
||||
- Added support for OpenResty/Nginx, moonscript, and Lapis debugging.
|
||||
- Added re-indentation of selected fragment or entire file.
|
||||
- Added line mapping support for debugging Lua-based languages (e.g. moonscript).
|
||||
- Added `editor.wrapindentmode` and `editor.wrapstartindent` settings.
|
||||
- Fixed debugger compatibility with Lua 5.2.
|
||||
- Fixed `F2` shortcut not working in file tree and watch panel.
|
||||
- Fixed replace-in-files when saving backup copy is turned off.
|
||||
|
||||
### Special thanks
|
||||
- To [sclark39](https://github.com/sclark39) for `format.apptitle` option to format IDE title.
|
||||
- To [Christoph Kubisch](https://github.com/pixeljetstream) for glslc improvements.
|
||||
- To [Yonaba](https://github.com/Yonaba/) for updated French translation.
|
||||
|
||||
### Improvements
|
||||
- Added support for nginx debugging (Mobdebug 0.564).
|
||||
- Added support for custom debugger initializer (global or interpreter-based).
|
||||
- Added line mapping support for debugging Lua-based languages (e.g. moonscript).
|
||||
- Added support to force local execution in console by prepending `!` (#326).
|
||||
- Added setting proper `arg[0]` value during debugging (fixes #329).
|
||||
- Added double click navigation in the Output window for unnamed files.
|
||||
- Added centering of line after double click in the Output window.
|
||||
- Added `editor.wrapindentmode` and `editor.wrapstartindent` settings.
|
||||
- Added a workaround for focus switching between controls on OSX (#89, #327).
|
||||
- Added assertion to ensure inserted editor is not in the notebook already.
|
||||
- Added `format.apptitle` option to format IDE title (thanks to @sclark39).
|
||||
- Added restoring cursor position after sorting/re-indenting.
|
||||
- Added `onEditorUserlistSelection` event for userlist selection (#166).
|
||||
- Added `onEditorAction` event for cut/copy/paste actions (#166).
|
||||
- Added package `GetEditorWithFocus` method (#166).
|
||||
- Added `editor.extradescent` option for line spacing (#305).
|
||||
- Added centering of line on page after re-loading file with a known position.
|
||||
- Added re-indentation of selected fragment or entire file (closes #324).
|
||||
- Added sorting of the entire file if nothing is selected.
|
||||
- Added `Edit | Source` sub-menu.
|
||||
- Added centering line on page after bookmark navigation.
|
||||
- Added `GetProjectTree`, `GetWatch`, and `GetStack` package calls (#166).
|
||||
- Added bookmark-toggle toolbar icon (#233).
|
||||
- Disabled message on failure to read symlinked folder content on Windows.
|
||||
- Disabled breakpoint toggling when editor is not in focus.
|
||||
- Disabled changing toolbar color with `auxwindow` as it only works for the dropdown.
|
||||
- Increase font size for code fragments in markup (#305).
|
||||
- glslc: change domain detection to be compatible with file.comp.glsl and file.tese
|
||||
- Removed checks for specific errors in Local/Remote console.
|
||||
- Removed focus handling workaround for editor tab changes (#89, #327).
|
||||
- Renamed `menuformatrecentprojects` to `format.menurecentprojects` (#305).
|
||||
- Removed handling of project dropdown in menu as it's no longer needed (#305).
|
||||
- Reorganized menu shortcut conflict handling (#233).
|
||||
- simplified glslc usage (compile and link based on file extensions)
|
||||
- treat unreal shaders as hlsl
|
||||
- Updated auto-complete logic to use configured spec separators.
|
||||
- Updated logic for populating placeholders in dropdown menus.
|
||||
- Updated french translation (thanks to @Yonaba)
|
||||
- Updated menu items to stay enabled only when appropriate object has focus.
|
||||
- Updated indentation logic for if/elseif/while/for split into 2+ lines (#324).
|
||||
- Updated indentation logic to ignore comments (#324).
|
||||
- Updated README with supported engines and installation instructions.
|
||||
- Updated breakpoint-toggle toolbar icon to better match other icons (#305).
|
||||
- Updated bookmark navigation to wrap around (#233).
|
||||
- Updating sorting to keep original line endings.
|
||||
- Upgraded metalua to v0.7.2.
|
||||
|
||||
### Fixes
|
||||
- Fixed setting control focus when the main frame is hidden.
|
||||
- Fixed loading packages with dashes in filenames (fixes #330).
|
||||
- Fixed toolbar to stay shown after failure to start debugging.
|
||||
- Fixed focus on the editor after closing a dialog on OSX (fixes #328).
|
||||
- Fixed crash on OSX when changing focus while the app is being closed (#327).
|
||||
- Fixed some toolbar buttons being enabled with no editor tab open.
|
||||
- Fixed toolbar stealing focus after closing floating panels and dropdowns (#327).
|
||||
- Fixed restoring control focus when the app gets focus on OSX (fixes #327).
|
||||
- Fixed activating editor when starting the app on OSX (#327).
|
||||
- Fixed auto-complete to not offer the word the cursor is on.
|
||||
- Fixed hiding auto-complete when the only option matches what's typed.
|
||||
- Fixed an error when all editor tabs are closed.
|
||||
- Fixed replace-in-files when saving backup copy is turned off.
|
||||
- Fixed re-indenting of anonymous functions in tables (#324).
|
||||
- Fixed `F2` shortcut not working in file tree and watch panel (#233).
|
||||
- Fixed debugger compatibility with Lua 5.2 (Mobdebug 0.561).
|
||||
|
||||
## v0.60 (May 11 2014)
|
||||
|
||||
### Highlights
|
||||
- Added support for switching breakpoints at run-time.
|
||||
- Added bookmark handling.
|
||||
- Added `Detach process` command to stop debugging and continue process.
|
||||
- Added detaching debugger server.
|
||||
- Added showing/hiding toolbar and status bar.
|
||||
- Simplified user interface and updated application icons.
|
||||
- Updated love2d API for v0.9.1.
|
||||
- Updated Moai API for v1.5.
|
||||
- Added `outputshell.usewrap` to set Output wrapping; on by default.
|
||||
- Added `editor.wrapflags` to configure line wrapping indicators.
|
||||
- Added `editor.foldflags`; set default to draw one line when folded.
|
||||
- Added `editor.foldtype` with box, cirle, arrow, and plus types.
|
||||
- Added `editor.extraascent` option to add line spacing.
|
||||
|
||||
### Special thanks
|
||||
- To [bartoleo](https://github.com/bartoleo) for italian translation update.
|
||||
- To [riidom](https://github.com/riidom) for german translation update.
|
||||
- To [sclark39](https://github.com/sclark39) for Copy Full Path implementation.
|
||||
- To [DanielSWolf](https://github.com/DanielSWolf) for Moai API update for v1.5.
|
||||
- To [madmaxoft](https://github.com/madmaxoft) for AnalyzeString patch.
|
||||
- To [crumblingstatue](https://github.com/crumblingstatue) for Zoom update.
|
||||
- To [SiENcE](https://github.com/SiENcE) for notepad++ colorscheme update.
|
||||
|
||||
### Improvements
|
||||
- Added new italian translations (thanks to @bartoleo)
|
||||
- Added Russian translation for new messages (#70).
|
||||
- Adding Copy Full Path to editor tabs, and a Clear Output Window option to the Output tab (thanks to @sclark39)
|
||||
- Added support for packages in config files (#166).
|
||||
- Added formatting for Recent Projects menu (#305).
|
||||
- Added `Detach process` command to stop debugging and continue process.
|
||||
- Added re/docking of Watch/Stack notebooks on tab background doubleclick (#305).
|
||||
- Added bookmark handling (closes #233).
|
||||
- Added `Clear items` to the Recent Files menu (ref #305).
|
||||
- Added recent files dropdown to the toolbar (ref #305).
|
||||
- Added applying new UI settings after upgrade (ref #305).
|
||||
- Added toolbar button dropdown with recent projects (ref #305).
|
||||
- Added `Choose Project Directory` to the toolbar (ref #305).
|
||||
- Added floating/docking of notebooks on tab background doubleclick (ref #305).
|
||||
- Added Recent Project menu refresh after switching projects (ref #305).
|
||||
- Added setting project directory by renaming the filetree root element (#305).
|
||||
- Added filetree popup menu with the list of projects (ref #305).
|
||||
- Added 'Recent Projects' menu (ref #305).
|
||||
- Added package `GetLaunchedProcess` call (ref #166).
|
||||
- Added `IsRunning` and `IsConnected` API calls for the debugger (ref #166).
|
||||
- Added `editor.wrapflags` to configure line wrapping indicators (ref #305).
|
||||
- Added explicit sorting of files in the filetree.
|
||||
- Added showing/hiding of the status bar (ref #305).
|
||||
- Added auto-showing toolbar when debugging starts (ref #305).
|
||||
- Added showing/hiding of the toolbar (ref #305).
|
||||
- Added `outputshell.usewrap` to set Output wrapping; on by default (ref #305).
|
||||
- Added `editor.foldflags`; set default to draw one line when folded (ref #305).
|
||||
- Added `editor.extraascent` option to add line spacing (ref #305).
|
||||
- Added explicit conversion to number for numeric settings.
|
||||
- Added `editor.foldtype` with box, cirle, arrow, and plus types (ref #305).
|
||||
- Added opening a new tab on double click on tab background (ref #305).
|
||||
- Added ActivateItem method to the filetree API (ref #166).
|
||||
- Added onFiletree* package events (ref #166).
|
||||
- Added setting margin mask to allow for different margin order.
|
||||
- Added support for switching breakpoints at run-time (closes #288).
|
||||
- Added stopping debugging when debugger server is detached/stopped.
|
||||
- Added opening file on one-click in icon/padding area in the filetree.
|
||||
- Added AnalyzeString function (thanks to @madmaxoft).
|
||||
- Added zooming for Output/Console windows (ref #290).
|
||||
- Added IDs for Zoom menu items (ref #290).
|
||||
- Add zoom actions with appropriate keyboard shortcuts to View menu (thanks to @crumblingstatue)
|
||||
- Added detaching debugger server.
|
||||
- Added skipping reporting for known globals in static analysis (closes #286).
|
||||
- Added support for running zbstudio script from any folder on OSX.
|
||||
- Adjusted `code` color in the comment markup for better visibility (#305).
|
||||
- Changed order of stopping debugger and saving settings (ref #305).
|
||||
- Cleaned unused variables and functions based on static analysis.
|
||||
- Disallowed closing Output/Console/Project tabs (fixes #310).
|
||||
- Disabled current project on the recent projects list (ref #305).
|
||||
- Disable function call indicator by default to reduce clutter (ref #305).
|
||||
- Disabled startng multiple find-in-files searches.
|
||||
- Disabled editing/dragging of the project directory in the filetree.
|
||||
- Enabled editor width auto-adjustment when wrapping is off.
|
||||
- Enable retina support (`hidpi=true`) by default on OSX (#305).
|
||||
- Increased default font size in the editor (ref #305).
|
||||
- Increased wait time for Gideros player to start for more reliable launching.
|
||||
- Made fold and marker margins wider (ref #305).
|
||||
- Made jump-to-line in the Output window to work faster and more reliably.
|
||||
- Moved `Project Directory` menu item lower to not activate on OSX (ref #305).
|
||||
- Moved code to populate `wx` and `wxstc` descriptions to API files.
|
||||
- Rearranged global functions in lua spec for simpler grouping (ref #79).
|
||||
- Reduced sash (border between subsections) in all notebooks (ref #305).
|
||||
- Reduced the line number margin width and default font size (ref #305).
|
||||
- Refactored editor config references.
|
||||
- Removed `Clear Dynamic Words` menu as it's rarely used.
|
||||
- Removed the gripper on the toolbar (ref #305).
|
||||
- Removed project selection dropdown from the filetree (ref #305).
|
||||
- Removed paragraph conversion from love2d API conversion script (ref #247).
|
||||
- Removed border around Output/Console panels (ref #305).
|
||||
- Removed deprecated `startfile` interpreter option.
|
||||
- Removed explicit margin numbers to make configuraton simpler.
|
||||
- Removed border around editor components.
|
||||
- Reordered markers to keep the curent line marker on top (#305).
|
||||
- Reorganized and updated configuration examples.
|
||||
- Set def linenumber font size as one smaller than editor font size (ref #305).
|
||||
- Switched to plain background for the toolbar (ref #305).
|
||||
- Switched to AuiToolBar as it provides buttons with dropdowns (ref #305).
|
||||
- Upgraded Mobdebug (0.56).
|
||||
- Upgraded debugger (mobdebug 0.553) to fix an issue with STEP command.
|
||||
- Upgraded copas to the current version (v1.2.1).
|
||||
- Updated default fonts for Windows and Linux for better looking ones (#305).
|
||||
- Update de.lua (thanks to @riidom)
|
||||
- Updated language files with new messages (#70).
|
||||
- Updated copyright messages.
|
||||
- Updated `Go To Line` menu item and its translations.
|
||||
- Updated build scripts with a fix for a wxlua compilation issue (#260).
|
||||
- Updated build prerequisites Linux install script.
|
||||
- Updated default indicator color to more neutral one (#305).
|
||||
- Updated OSX build script to use 10.7 SDK with 10.6 min-version (#260).
|
||||
- Updated Mobdebug (0.555) to add support for `pause` debugger call.
|
||||
- Updated lua interpreter to remove caching of executable path.
|
||||
- Updated resetting pid only after completing non-debbugged process.
|
||||
- Updated shortcut for Recent File navigation (ref #305).
|
||||
- Updated application icons (ref #305).
|
||||
- Updated stack/watch panel captions to be invisible (ref #305).
|
||||
- Updated interpreters to check `ProgramFiles` env variable on Windows.
|
||||
- Updated panel captions to be invisible (rev #305).
|
||||
- Updated 'window unhide' logic (Windows only) to be called less frequently.
|
||||
- Updated love2d interpreter to not hide the application window.
|
||||
- Updated file sorting to be case-insensitive on all platforms.
|
||||
- Updated filetree menu to use 'Edit Project Directory' on root element (#305).
|
||||
- Updated love2d API to fix typos in descriptions (ref #247).
|
||||
- Updated love2d API for v0.9.1 (ref #247).
|
||||
- Updated love2d API conversion script to handle top-level functions (ref #247).
|
||||
- Updated `PackageUnRegister` call to return the package on success (ref #166).
|
||||
- Updated fold/wrap flag handling to work with wxwidgets 2.8 (ref #305).
|
||||
- Updated breakpoint/currentline markers for less contrast colors (ref #305).
|
||||
- Updated default folding to use lighter colors (ref #305).
|
||||
- Updated default colors to have less contrast (ref #305).
|
||||
- Updated Open file dialog to use current file or project location (closes #303).
|
||||
- Updated Moai API for v1.5 (thanks to @DanielSWolf).
|
||||
- Updated `autoanalyzer` option to more common spelling (analizer -> analyzer).
|
||||
- Updated auto-complete to show in IDLE event for smoother processing.
|
||||
- -minor color changes to notepad++ colorscheme (thanks to @SiENcE).
|
||||
|
||||
### Incompatibilities
|
||||
- Added opening a new tab on double click on tab background.
|
||||
- Added re/docking of Watch/Stack notebooks on tab background doubleclick.
|
||||
- Enabled retina support (`hidpi=true`) by default on OSX.
|
||||
- Removed deprecated `startfile` interpreter option; use `startwith` option instead.
|
||||
- Updated file sorting to be case-insensitive on all platforms.
|
||||
- Updated `autoanalyzer` option to more common spelling (analizer -> analyzer).
|
||||
- wxwidgets 2.8 is no longer supported (wxwidgets 2.9.5+ required).
|
||||
|
||||
### Fixes
|
||||
- Fixed Corona interpreter to clean debugger in `plugin` folder (Win).
|
||||
- Fixed file tree activation of a deleted file.
|
||||
- Fixed switching to full screen and restoring status bar on OSX (ref #305).
|
||||
- Fixed right-click handling in filetree on OSX broken by 3709f61f (ref #166).
|
||||
- Fixed usage of `self` in one of package API calls (ref #166).
|
||||
- Fixed find dialog to stay on top after search directory selection on OSX.
|
||||
- Fixed search result navigation after clicking beyond the end of line.
|
||||
- Fixed an issue with running processes not terminated when closing IDE.
|
||||
- Fixed an error after manual canceling Find-in-files dialog.
|
||||
- Fixed an issue with deleting column-based selection (fixes #300).
|
||||
- Fixed an error in variable indicator processing.
|
||||
- Fixed looping when `valuetype` creates self-reference in APIs (ref #297).
|
||||
- Fixed `elseif` auto-indentation (fixes #294).
|
||||
- Fixed focus for Find field in the find dialog on some instances of OSX.
|
||||
|
||||
## 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
|
||||
|
||||
51
README.md
51
README.md
@@ -1,9 +1,20 @@
|
||||
# Project Description
|
||||
|
||||
[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/).
|
||||
[ZeroBrane Studio](http://studio.zerobrane.com/) is a lightweight cross-platform Lua IDE with code completion,
|
||||
syntax highlighting, remote debugger, code analyzer, live coding,
|
||||
and debugging 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),
|
||||
[Adobe Lightroom](http://notebook.kulchenko.com/zerobrane/debugging-lightroom-plugins-zerobrane-studio-ide),
|
||||
[OpenResty/Nginx](http://notebook.kulchenko.com/zerobrane/debugging-openresty-nginx-lua-scripts-with-zerobrane-studio)
|
||||
and others). It originated from the [Estrela Editor](http://www.luxinia.de/index.php/Estrela/).
|
||||
|
||||

|
||||
|
||||
## Features
|
||||
|
||||
@@ -15,17 +26,20 @@ MobileLua, GSL-shell, and others). It originated from the [Estrela Editor](http:
|
||||
[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 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, and keywords;
|
||||
- apis (`api/`): for code completion and tooltips;
|
||||
* [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;
|
||||
- config (`cfg/`): contains style, color themes, and other settings;
|
||||
- packages (`packages/`): plugins that provide additional functionality;
|
||||
- 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
|
||||
@@ -35,16 +49,17 @@ and Corona SDK ([demo](http://notebook.kulchenko.com/zerobrane/debugging-and-liv
|
||||
* [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
|
||||
## Installation
|
||||
|
||||

|
||||
ZeroBrane Studio can be installed into and run from any folder.
|
||||
No compilation is needed, although the scripts to compile required libraries for Windows, OSX, and Linux platforms are available in the `build/` folder.
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
Open file(s):
|
||||
zbstudio <filename> [<filename>...]
|
||||
any non-option will be treated as filename
|
||||
any non-option will be treated as a file to open or a directory to set as the project directory
|
||||
|
||||
Set project directory:
|
||||
zbstudio <project directory> [<filename>...]
|
||||
@@ -59,6 +74,8 @@ Loading custom configuration:
|
||||
e.g.: zbstudio -cfg cfg/estrela.lua
|
||||
```
|
||||
|
||||
If you are loading a file, you can also request the cursor to be set on a particular line or at a particular position by using `filename:<line>` and `filename:p<pos>` syntax (0.71+).
|
||||
|
||||
## Author
|
||||
|
||||
### ZeroBrane Studio and MobDebug
|
||||
|
||||
@@ -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,7 +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
|
||||
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
5654
api/lua/corona.lua
5654
api/lua/corona.lua
File diff suppressed because it is too large
Load Diff
2637
api/lua/love2d.lua
2637
api/lua/love2d.lua
File diff suppressed because it is too large
Load Diff
2339
api/lua/luxgfx.lua
2339
api/lua/luxgfx.lua
File diff suppressed because one or more lines are too long
@@ -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)",
|
||||
},
|
||||
|
||||
18168
api/lua/moai.lua
18168
api/lua/moai.lua
File diff suppressed because it is too large
Load Diff
@@ -1,16 +1,24 @@
|
||||
local api = {}
|
||||
for key in pairs(wx) do
|
||||
api[key] = {
|
||||
type = (type(wx[key]) == "function" and "function" or "value"),
|
||||
description = "",
|
||||
returns = "",
|
||||
}
|
||||
local function populateAPI(t)
|
||||
local api = {}
|
||||
for k,v in pairs(t) do
|
||||
api[k] = {
|
||||
type = (type(v) == "function" and "function" or "value"),
|
||||
description = "",
|
||||
returns = "",
|
||||
}
|
||||
end
|
||||
return api
|
||||
end
|
||||
|
||||
return {
|
||||
wx = {
|
||||
type = "lib",
|
||||
description = "WX lib",
|
||||
childs = api
|
||||
}
|
||||
}
|
||||
wx = {
|
||||
type = "lib",
|
||||
description = "wx lib",
|
||||
childs = populateAPI(wx),
|
||||
},
|
||||
wxstc = {
|
||||
type = "lib",
|
||||
description = "wxSTC lib",
|
||||
childs = populateAPI(wxstc),
|
||||
},
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
BIN
bin/liblua.dylib
Normal file → Executable file
BIN
bin/liblua.dylib
Normal file → Executable file
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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)
|
||||
|
||||
@@ -7,3 +7,5 @@ sudo yum install git
|
||||
sudo yum install svn
|
||||
sudo yum install cmake
|
||||
sudo yum install gtk2-devel
|
||||
sudo yum install wget
|
||||
sudo yum install sqlite
|
||||
|
||||
@@ -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
|
||||
@@ -189,6 +164,10 @@ if [ $BUILD_WXLUA ]; then
|
||||
# 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
|
||||
|
||||
# (temporary) fix for compilation issue in wxlua using wxwidgets 3.1+ (r238)
|
||||
sed -i 's/{ "wxSTC_COFFEESCRIPT_HASHQUOTEDSTRING", wxSTC_COFFEESCRIPT_HASHQUOTEDSTRING },/\/\/ removed by ZBS build process/' modules/wxbind/src/wxstc_bind.cpp
|
||||
|
||||
cmake -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX="$INSTALL_DIR" -DCMAKE_BUILD_TYPE=MinSizeRel -DBUILD_SHARED_LIBS=FALSE \
|
||||
-DwxWidgets_CONFIG_EXECUTABLE="$INSTALL_DIR/bin/wx-config" \
|
||||
-DwxWidgets_COMPONENTS="stc;html;aui;adv;core;net;base" \
|
||||
|
||||
@@ -9,7 +9,7 @@ INSTALL_DIR="$PWD/deps"
|
||||
# Mac OS X global settings
|
||||
MACOSX_ARCH="i386"
|
||||
MACOSX_VERSION="10.6"
|
||||
MACOSX_SDK_PATH="/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.6.sdk"
|
||||
MACOSX_SDK_PATH="/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.7.sdk"
|
||||
|
||||
# number of parallel jobs used for building
|
||||
MAKEFLAGS="-j4"
|
||||
@@ -136,10 +136,8 @@ if [ $BUILD_WXWIDGETS ]; then
|
||||
if [ -d $MACOSX_SDK_PATH ]; then
|
||||
MINSDK="--with-macosx-sdk=$MACOSX_SDK_PATH"
|
||||
fi
|
||||
# fix auto-complete crash by reverting an earlier revision
|
||||
# http://trac.wxwidgets.org/ticket/15008#comment:12
|
||||
svn merge -r 74098:74097 .
|
||||
./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 $MINSDK \
|
||||
@@ -193,6 +191,10 @@ if [ $BUILD_WXLUA ]; then
|
||||
# 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
|
||||
|
||||
# (temporary) fix for compilation issue in wxlua using wxwidgets 3.1+ (r238)
|
||||
sed -i 's/{ "wxSTC_COFFEESCRIPT_HASHQUOTEDSTRING", wxSTC_COFFEESCRIPT_HASHQUOTEDSTRING },/\/\/ removed by ZBS build process/' modules/wxbind/src/wxstc_bind.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 $MINSDK \
|
||||
-DCMAKE_C_COMPILER=/usr/bin/gcc -DCMAKE_CXX_COMPILER=/usr/bin/g++ -DwxWidgets_CONFIG_EXECUTABLE="$INSTALL_DIR/bin/wx-config" \
|
||||
|
||||
@@ -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,11 @@ 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"
|
||||
# (temporary) fix for compilation issue in wxlua using wxwidgets 3.1+ (r238)
|
||||
sed -i 's/{ "wxSTC_COFFEESCRIPT_HASHQUOTEDSTRING", wxSTC_COFFEESCRIPT_HASHQUOTEDSTRING },/\/\/ removed by ZBS build process/' modules/wxbind/src/wxstc_bind.cpp
|
||||
|
||||
[ -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 \
|
||||
|
||||
@@ -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
|
||||
|
||||
151
cfg/i18n/cn.lua
151
cfg/i18n/cn.lua
@@ -1,14 +1,19 @@
|
||||
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 Project Directory"] = nil, -- src\editor\filetree.lua
|
||||
["&Edit Watch"] = "编辑监视", -- src\editor\debugger.lua
|
||||
["&Edit"] = "编辑", -- src\editor\menu_edit.lua
|
||||
["&File"] = "文件", -- src\editor\menu_file.lua
|
||||
@@ -16,82 +21,105 @@ return {
|
||||
["&Find Next"] = "查找下一个", -- src\editor\findreplace.lua
|
||||
["&Find"] = "查找", -- src\editor\menu_search.lua
|
||||
["&Fold/Unfold All"] = "全 折叠/展开", -- src\editor\menu_edit.lua
|
||||
["&Goto Line"] = "到...行", -- src\editor\menu_search.lua
|
||||
["&Frequently Asked Questions"] = nil, -- src\editor\menu_help.lua
|
||||
["&Getting Started Guide"] = nil, -- src\editor\menu_help.lua
|
||||
["&Go To 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
|
||||
["&Status Bar"] = nil, -- src\editor\menu_view.lua
|
||||
["&Subdirectories"] = "子文件夹", -- src\editor\findreplace.lua
|
||||
["&Undo"] = "撤消", -- src\editor\editor.lua, src\editor\menu_edit.lua
|
||||
["&Tool Bar"] = nil, -- src\editor\menu_view.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
|
||||
["Bookmark"] = nil, -- src\editor\menu_edit.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
|
||||
["Can't stop debugger server as it is not started."] = nil, -- src\editor\debugger.lua
|
||||
["Cancel"] = "取消", -- 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
|
||||
["Cancelled by the user."] = nil, -- src\editor\findreplace.lua
|
||||
["Choose a project directory"] = "选择项目文件夹", -- src\editor\findreplace.lua, src\editor\menu_project.lua, src\editor\gui.lua, src\editor\filetree.lua
|
||||
["Choose..."] = "请选...", -- src\editor\menu_project.lua, src\editor\filetree.lua
|
||||
["Clear Items"] = nil, -- src\editor\menu_file.lua
|
||||
["Clear items from this list"] = nil, -- src\editor\menu_file.lua
|
||||
["Clear the output window before compiling or debugging"] = "编译或除错前清除输出视窗", -- src\editor\menu_project.lua
|
||||
["Close &Other Pages"] = "关闭其他页面", -- src\editor\gui.lua
|
||||
["Close A&ll Pages"] = "关闭全部页面", -- src\editor\gui.lua
|
||||
["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
|
||||
["Debugger server stopped at %s:%d."] = nil, -- 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
|
||||
["Detach &Process"] = nil, -- src\editor\menu_project.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 +127,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,25 +147,30 @@ 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 Line"] = "到...行", -- src\editor\menu_search.lua
|
||||
["Go To Next Bookmark"] = nil, -- src\editor\menu_edit.lua
|
||||
["Go To Previous Bookmark"] = nil, -- src\editor\menu_edit.lua
|
||||
["Go to a selected line"] = "到所选的行", -- src\editor\menu_search.lua
|
||||
["Goto Line"] = "到...行", -- src\editor\menu_search.lua
|
||||
["INS"] = "INS", -- src\editor\editor.lua
|
||||
["In Files"] = "在档案里", -- src\editor\findreplace.lua
|
||||
["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
|
||||
@@ -148,68 +181,85 @@ return {
|
||||
["Program starting as '%s'."] = "程式以 '%s' 执行", -- src\editor\output.lua
|
||||
["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 Directory"] = "项目文件夹", -- src\editor\menu_project.lua, src\editor\filetree.lua
|
||||
["Project history"] = nil, -- src\editor\menu_file.lua
|
||||
["Project"] = "项目", -- src\editor\gui.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
|
||||
["Recent &Projects"] = nil, -- src\editor\menu_file.lua
|
||||
["Recent Files"] = "最近的文档", -- src\editor\menu_file.lua
|
||||
["Redo last edit undone"] = "重做最后被取消的编辑", -- src\editor\menu_edit.lua
|
||||
["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
|
||||
["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
|
||||
["Replacing"] = "更换中", -- src\editor\findreplace.lua
|
||||
["Reset to default layout"] = "重置缺省布局", -- src\editor\menu_view.lua
|
||||
["Resets the dynamic word list for autocompletion"] = "为自动补全重置动态word list", -- src\editor\menu_edit.lua
|
||||
["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
|
||||
["Sel: %d/%d"] = nil, -- src\editor\editor.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
|
||||
["Set the project directory to be used"] = "设置项目文件夹", -- src\editor\menu_project.lua, src\editor\filetree.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
|
||||
["Show/Hide the status bar"] = nil, -- src\editor\menu_view.lua
|
||||
["Show/Hide the toolbar"] = nil, -- src\editor\menu_view.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 debugging and continue running the process"] = nil, -- 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 Bookmark"] = nil, -- src\editor\menu_edit.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 +270,17 @@ 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
|
||||
["Zoom In"] = nil, -- src\editor\menu_view.lua
|
||||
["Zoom Out"] = nil, -- src\editor\menu_view.lua
|
||||
["Zoom to 100%"] = nil, -- src\editor\menu_view.lua
|
||||
["Zoom"] = nil, -- src\editor\menu_view.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
|
||||
}
|
||||
|
||||
153
cfg/i18n/de.lua
153
cfg/i18n/de.lua
@@ -5,12 +5,16 @@ 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 Project Directory"] = "Projektverzeichnis ändern", -- src\editor\filetree.lua
|
||||
["&Edit Watch"] = "&Beobachtungspunkt bearbeiten", -- src\editor\debugger.lua
|
||||
["&Edit"] = "&Bearbeiten", -- src\editor\menu_edit.lua
|
||||
["&File"] = "&Datei", -- src\editor\menu_file.lua
|
||||
@@ -18,76 +22,98 @@ 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
|
||||
["&Goto Line"] = "&Gehe zu Zeile", -- src\editor\menu_search.lua
|
||||
["&Frequently Asked Questions"] = "&FAQ", -- src\editor\menu_help.lua
|
||||
["&Getting Started Guide"] = "&Anfängerleitfaden", -- src\editor\menu_help.lua
|
||||
["&Go To 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
|
||||
["&Status Bar"] = "S&tatuszeile", -- src\editor\menu_view.lua
|
||||
["&Subdirectories"] = "&Unterverzeichnisse", -- src\editor\findreplace.lua
|
||||
["&Undo"] = "&Rückgängig", -- src\editor\editor.lua, src\editor\menu_edit.lua
|
||||
["&Tool Bar"] = "&Werkzeugleiste", -- src\editor\menu_view.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
|
||||
["Bookmark"] = "Lese&zeichen", -- 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
|
||||
["Can't stop debugger server as it is not started."] = "Kann Debugserver nicht stoppen wenn er vorher nicht gestartet wurde.", -- src\editor\debugger.lua
|
||||
["Cancel"] = "Abbrechen", -- 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
|
||||
["Cancelled by the user."] = "Durch Benutzer abgebrochen.", -- src\editor\findreplace.lua
|
||||
["Choose a project directory"] = "Projektverzeichnis auswählen", -- src\editor\findreplace.lua, src\editor\menu_project.lua, src\editor\gui.lua, src\editor\filetree.lua
|
||||
["Choose..."] = "Wählen...", -- src\editor\menu_project.lua, src\editor\filetree.lua
|
||||
["Clear Items"] = "Liste &löschen", -- src\editor\menu_file.lua
|
||||
["Clear items from this list"] = "Diese Liste löschen", -- src\editor\menu_file.lua
|
||||
["Clear the output window before compiling or debugging"] = "Vor Kompilieren oder Debuggen das Ausgabefenster löschen", -- src\editor\menu_project.lua
|
||||
["Close &Other Pages"] = "A&ndere Seiten schließen", -- src\editor\gui.lua
|
||||
["Close A&ll Pages"] = "&Alle Seiten schließen", -- src\editor\gui.lua
|
||||
["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
|
||||
["Debugger server stopped at %s:%d."] = "Debugserver gestoppt 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
|
||||
["Detach &Process"] = "Prozeß abkoppeln", -- src\editor\menu_project.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 +129,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
|
||||
@@ -122,25 +149,29 @@ return {
|
||||
["Found"] = "Gefunden", -- src\editor\findreplace.lua
|
||||
["Full &Screen"] = "&Vollbild", -- src\editor\menu_view.lua
|
||||
["Go To Definition"] = "Gehe zu Definition", -- src\editor\editor.lua
|
||||
["Go To Line"] = "Gehe zu Zeile", -- src\editor\menu_search.lua
|
||||
["Go To Next Bookmark"] = "Zu nächstem Lesezeichen", -- src\editor\menu_edit.lua
|
||||
["Go To Previous Bookmark"] = "Zu vorherigem Lesezeichen", -- src\editor\menu_edit.lua
|
||||
["Go to a selected line"] = "Gehe zu ausgewählter Zeile", -- src\editor\menu_search.lua
|
||||
["Goto Line"] = "Gehe zu Zeile", -- src\editor\menu_search.lua
|
||||
["INS"] = "INS", -- src\editor\editor.lua
|
||||
["In Files"] = "In Dateien", -- src\editor\findreplace.lua
|
||||
["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
|
||||
@@ -151,12 +182,15 @@ return {
|
||||
["Program starting as '%s'."] = "Programm gestartet als '%s'.", -- src\editor\output.lua
|
||||
["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 Directory"] = "&Projektverzeichnis", -- src\editor\menu_project.lua, src\editor\filetree.lua
|
||||
["Project history"] = "Liste bisheriger Projekte", -- src\editor\menu_file.lua
|
||||
["Project"] = "Projekt", -- src\editor\gui.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
|
||||
["Recent &Projects"] = "Letzte &Projekte", -- src\editor\menu_file.lua
|
||||
["Recent Files"] = "Letzte Dateien", -- src\editor\menu_file.lua
|
||||
["Redo last edit undone"] = "Stelle letzte rückgängig gemachte Bearbeitung wieder her", -- src\editor\menu_edit.lua
|
||||
["Refused a request to start a new debugging session as there is one in progress already."] = "Starten einer neuen Debuggingsession abgelehnt, da bereits eine läuft.", -- src\editor\debugger.lua
|
||||
@@ -169,52 +203,64 @@ return {
|
||||
["Replaced"] = "Ersetzt:", -- src\editor\findreplace.lua
|
||||
["Replacing"] = "Am Ersetzen", -- src\editor\findreplace.lua
|
||||
["Reset to default layout"] = "Standard-Layout wiederherstellen", -- src\editor\menu_view.lua
|
||||
["Resets the dynamic word list for autocompletion"] = "Zurücksetzen der Liste der dynamischen Wörter für Autovervollständigung", -- src\editor\menu_edit.lua
|
||||
["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
|
||||
["Sel: %d/%d"] = "Ausgew.: %d/%d", -- src\editor\editor.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
|
||||
["Set the project directory to be used"] = "Lege zu benutzendes Projektverzeichnis fest", -- src\editor\menu_project.lua, src\editor\filetree.lua
|
||||
["Settings: System"] = "Einstellungen: System", -- src\editor\menu_edit.lua
|
||||
["Settings: User"] = "Einstellungen: Nutzer", -- src\editor\menu_edit.lua
|
||||
["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
|
||||
["Show/Hide the status bar"] = "Statuszeile zeigen/verstecken", -- src\editor\menu_view.lua
|
||||
["Show/Hide the toolbar"] = "Werkzeugleiste zeigen/verstecken", -- src\editor\menu_view.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 debugging and continue running the process"] = "Beende debuggen und setze den Prozeß fort", -- 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 Bookmark"] = "Lesezeichen setzen/löschen", -- src\editor\menu_edit.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 +271,17 @@ 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
|
||||
["Zoom In"] = "Hineinzoomen", -- src\editor\menu_view.lua
|
||||
["Zoom Out"] = "Herauszoomen", -- src\editor\menu_view.lua
|
||||
["Zoom to 100%"] = "Zoom zurücksetzen (100%)", -- src\editor\menu_view.lua
|
||||
["Zoom"] = "Zoom", -- src\editor\menu_view.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
|
||||
}
|
||||
|
||||
181
cfg/i18n/es.lua
181
cfg/i18n/es.lua
@@ -1,85 +1,120 @@
|
||||
-- Traducción realiazada por Iñigo Sola
|
||||
-- para la versión ZeroBrane Studio 17bdb48
|
||||
-- 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 Project Directory"] = nil, -- src\editor\filetree.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
|
||||
["&Goto Line"] = "Ir a línea", -- src\editor\menu_search.lua
|
||||
["&Frequently Asked Questions"] = nil, -- src\editor\menu_help.lua
|
||||
["&Getting Started Guide"] = nil, -- src\editor\menu_help.lua
|
||||
["&Go To 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
|
||||
["&Status Bar"] = nil, -- src\editor\menu_view.lua
|
||||
["&Subdirectories"] = nil, -- src\editor\findreplace.lua
|
||||
["&Tool Bar"] = nil, -- src\editor\menu_view.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
|
||||
["Bookmark"] = nil, -- 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\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
|
||||
["Clear &Dynamic Words"] = "Limpiar las palabras dinámicas", -- src\editor\menu_edit.lua
|
||||
["Can't stop debugger server as it is not started."] = nil, -- src\editor\debugger.lua
|
||||
["Cancel"] = nil, -- src\editor\findreplace.lua
|
||||
["Cancelled by the user."] = nil, -- src\editor\findreplace.lua
|
||||
["Choose a project directory"] = "Elegir el directorio del proyecto", -- src\editor\findreplace.lua, src\editor\menu_project.lua, src\editor\gui.lua, src\editor\filetree.lua
|
||||
["Choose..."] = nil, -- src\editor\menu_project.lua, src\editor\filetree.lua
|
||||
["Clear Items"] = nil, -- src\editor\menu_file.lua
|
||||
["Clear items from this list"] = nil, -- src\editor\menu_file.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
|
||||
["Close A&ll Pages"] = nil, -- src\editor\gui.lua
|
||||
["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
|
||||
["Debugger server stopped at %s:%d."] = nil, -- 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
|
||||
["Detach &Process"] = nil, -- src\editor\menu_project.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 +130,51 @@ 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 Line"] = "Ir a línea", -- src\editor\menu_search.lua
|
||||
["Go To Next Bookmark"] = nil, -- src\editor\menu_edit.lua
|
||||
["Go To Previous Bookmark"] = nil, -- src\editor\menu_edit.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
|
||||
@@ -133,58 +183,85 @@ return {
|
||||
["Program starting as '%s'."] = "Programa iniciado como '%s'.", -- src\editor\output.lua
|
||||
["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 Directory"] = nil, -- src\editor\menu_project.lua, src\editor\filetree.lua
|
||||
["Project history"] = nil, -- src\editor\menu_file.lua
|
||||
["Project"] = "Proyecto", -- src\editor\gui.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 &Projects"] = nil, -- src\editor\menu_file.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
|
||||
["Sel: %d/%d"] = nil, -- src\editor\editor.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
|
||||
["Set the project directory to be used"] = nil, -- src\editor\menu_project.lua, src\editor\filetree.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
|
||||
["Show/Hide the status bar"] = nil, -- src\editor\menu_view.lua
|
||||
["Show/Hide the toolbar"] = nil, -- src\editor\menu_view.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 debugging and continue running the process"] = nil, -- 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 Bookmark"] = nil, -- src\editor\menu_edit.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 +272,17 @@ 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
|
||||
["Zoom In"] = nil, -- src\editor\menu_view.lua
|
||||
["Zoom Out"] = nil, -- src\editor\menu_view.lua
|
||||
["Zoom to 100%"] = nil, -- src\editor\menu_view.lua
|
||||
["Zoom"] = nil, -- src\editor\menu_view.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
|
||||
}
|
||||
|
||||
143
cfg/i18n/fr.lua
143
cfg/i18n/fr.lua
@@ -5,12 +5,16 @@ 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 Project Directory"] = "&Modifier le répertoire de projet", -- src\editor\filetree.lua
|
||||
["&Edit Watch"] = "&Modifier une expression", -- src\editor\debugger.lua
|
||||
["&Edit"] = "É&dition", -- src\editor\menu_edit.lua
|
||||
["&File"] = "&Fichier", -- src\editor\menu_file.lua
|
||||
@@ -18,76 +22,98 @@ 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
|
||||
["&Goto Line"] = "&Aller à la ligne", -- src\editor\menu_search.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
|
||||
["&Go To 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
|
||||
["&Status Bar"] = "&Barre d'état", -- src\editor\menu_view.lua
|
||||
["&Subdirectories"] = "&Sous-répertoires", -- src\editor\findreplace.lua
|
||||
["&Undo"] = "&Annuler", -- src\editor\editor.lua, src\editor\menu_edit.lua
|
||||
["&Tool Bar"] = "&Barre d'outils", -- src\editor\menu_view.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
|
||||
["Bookmark"] = "&Marque-pages", -- src\editor\menu_edit.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
|
||||
["Can't stop debugger server as it is not started."] = "Impossible d'arrêter le serveur de débogage car il n'a pas été démarré", -- src\editor\debugger.lua
|
||||
["Cancel"] = "Annuler", -- 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
|
||||
["Cancelled by the user."] = "Annulé par l'utilisateur.", -- src\editor\findreplace.lua
|
||||
["Choose a project directory"] = "Choisissez un répertoire de projet", -- src\editor\findreplace.lua, src\editor\menu_project.lua, src\editor\gui.lua, src\editor\filetree.lua
|
||||
["Choose..."] = "Choisir...", -- src\editor\menu_project.lua, src\editor\filetree.lua
|
||||
["Clear Items"] = "Effacer les éléments", -- src\editor\menu_file.lua
|
||||
["Clear items from this list"] = "Effacer les éléments de cette liste", -- src\editor\menu_file.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
|
||||
["Close &Other Pages"] = "Fermer les &autres pages", -- src\editor\gui.lua
|
||||
["Close A&ll Pages"] = "Fermer &toutes les pages", -- src\editor\gui.lua
|
||||
["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
|
||||
["Debugger server stopped at %s:%d."] = "Serveur de débogage stoppé à %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
|
||||
["Detach &Process"] = "Détacher le &processus", -- src\editor\menu_project.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 +129,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
|
||||
@@ -122,25 +149,29 @@ return {
|
||||
["Found"] = "Occurrences trouvées :", -- src\editor\findreplace.lua
|
||||
["Full &Screen"] = "&Plein écran", -- src\editor\menu_view.lua
|
||||
["Go To Definition"] = "Aller à la définition", -- src\editor\editor.lua
|
||||
["Go To Line"] = "Aller à la ligne", -- src\editor\menu_search.lua
|
||||
["Go To Next Bookmark"] = "Aller au marque-page suivant", -- src\editor\menu_edit.lua
|
||||
["Go To Previous Bookmark"] = "Aller au marque-page précédent", -- src\editor\menu_edit.lua
|
||||
["Go to a selected line"] = "Aller à la ligne sélectionnée", -- src\editor\menu_search.lua
|
||||
["Goto Line"] = "Aller à la ligne", -- src\editor\menu_search.lua
|
||||
["INS"] = "INS", -- src\editor\editor.lua
|
||||
["In Files"] = "Dans les fichiers", -- src\editor\findreplace.lua
|
||||
["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
|
||||
@@ -151,12 +182,15 @@ return {
|
||||
["Program starting as '%s'."] = "Programme démarré en tant que '%s'.", -- src\editor\output.lua
|
||||
["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 Directory"] = "Répertoire de projet", -- src\editor\menu_project.lua, src\editor\filetree.lua
|
||||
["Project history"] = "Historique de projet", -- src\editor\menu_file.lua
|
||||
["Project"] = "Projet", -- src\editor\gui.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
|
||||
["Recent &Projects"] = "&Projets récents", -- src\editor\menu_file.lua
|
||||
["Recent Files"] = "Fichiers récents", -- src\editor\menu_file.lua
|
||||
["Redo last edit undone"] = "Rétablir la dernière modification", -- src\editor\menu_edit.lua
|
||||
["Refused a request to start a new debugging session as there is one in progress already."] = "Une requête de lancement de débogage a été refusée car une session de débogage est déjà en cours.", -- src\editor\debugger.lua
|
||||
@@ -169,52 +203,64 @@ return {
|
||||
["Replaced"] = "Occurrences remplacées :", -- src\editor\findreplace.lua
|
||||
["Replacing"] = "Remplacement de", -- src\editor\findreplace.lua
|
||||
["Reset to default layout"] = "Restaurer l'affichage par défaut", -- src\editor\menu_view.lua
|
||||
["Resets the dynamic word list for autocompletion"] = "Réinitialiser la liste des mots dynamiques pour l'auto-complétion", -- src\editor\menu_edit.lua
|
||||
["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
|
||||
["Sel: %d/%d"] = "Sel: %d/%d", -- src\editor\editor.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
|
||||
["Set the project directory to be used"] = "Définir le répertoire de projet à utiliser", -- src\editor\menu_project.lua, src\editor\filetree.lua
|
||||
["Settings: System"] = "Paramètres : Système", -- src\editor\menu_edit.lua
|
||||
["Settings: User"] = "Paramètres : Utilisateur", -- src\editor\menu_edit.lua
|
||||
["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
|
||||
["Show/Hide the status bar"] = "Afficher/Masquer la barre de statut", -- src\editor\menu_view.lua
|
||||
["Show/Hide the toolbar"] = "Afficher/Masquer la barre d'outils", -- src\editor\menu_view.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 debugging and continue running the process"] = "Arrêter le débogage et continuer l'exécution du processus", -- 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 Bookmark"] = "Créer/Supprimer un marque-page", -- src\editor\menu_edit.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 +271,17 @@ 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
|
||||
["Zoom In"] = "Zoomer", -- src\editor\menu_view.lua
|
||||
["Zoom Out"] = "Dézoomer", -- src\editor\menu_view.lua
|
||||
["Zoom to 100%"] = "Zoomer à 100%", -- src\editor\menu_view.lua
|
||||
["Zoom"] = "Zoom", -- src\editor\menu_view.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
|
||||
}
|
||||
|
||||
185
cfg/i18n/it.lua
185
cfg/i18n/it.lua
@@ -1,82 +1,119 @@
|
||||
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 Project Directory"] = "Modifica directory di progetto", -- src\editor\filetree.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
|
||||
["&Goto Line"] = "Vai a riga", -- src\editor\menu_search.lua
|
||||
["&Frequently Asked Questions"] = "Domande &Frequenti", -- src\editor\menu_help.lua
|
||||
["&Getting Started Guide"] = "&Guida Introduttiva", -- src\editor\menu_help.lua
|
||||
["&Go To 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
|
||||
["&Status Bar"] = "Barra di stato", -- src\editor\menu_view.lua
|
||||
["&Subdirectories"] = "Sotto Directory", -- src\editor\findreplace.lua
|
||||
["&Tool Bar"] = "Barra degli strumenti", -- src\editor\menu_view.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
|
||||
["Bookmark"] = "Segnalibro", -- src\editor\menu_edit.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
|
||||
["Can't stop debugger server as it is not started."] = "Impossibile fermare il server debugger perchè non è stato avviato", -- src\editor\debugger.lua
|
||||
["Cancel"] = "Annulla", -- src\editor\findreplace.lua
|
||||
["Cancelled by the user."] = "Annullato dall'utente", -- src\editor\findreplace.lua
|
||||
["Choose a project directory"] = "Scegli la directory di un progetto", -- src\editor\findreplace.lua, src\editor\menu_project.lua, src\editor\gui.lua, src\editor\filetree.lua
|
||||
["Choose..."] = "Scegli...", -- src\editor\menu_project.lua, src\editor\filetree.lua
|
||||
["Clear Items"] = "Pulisci elementi", -- src\editor\menu_file.lua
|
||||
["Clear items from this list"] = "Pulisci elementi della lista", -- src\editor\menu_file.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
|
||||
["Debugger server started at %s:%d."] = "Server Debugger iniziato %s:%d.", -- src\editor\debugger.lua
|
||||
["Debugger server stopped at %s:%d."] = "Server Debugger fermato %s:%d.", -- 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
|
||||
["Detach &Process"] = "Scollega Processo", -- src\editor\menu_project.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 +129,51 @@ 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 Line"] = "Vai alla riga", -- src\editor\menu_search.lua
|
||||
["Go To Next Bookmark"] = "Vai al Prossimo Segnalibro", -- src\editor\menu_edit.lua
|
||||
["Go To Previous Bookmark"] = "Vai al Precedente Segnalibro", -- src\editor\menu_edit.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
|
||||
@@ -130,58 +182,85 @@ return {
|
||||
["Program starting as '%s'."] = "Programma partito da '%s'.", -- src\editor\output.lua
|
||||
["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 Directory"] = "Directory del Progetto", -- src\editor\menu_project.lua, src\editor\filetree.lua
|
||||
["Project history"] = "Storia del Progetto", -- src\editor\menu_file.lua
|
||||
["Project"] = "Progetto", -- src\editor\gui.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 &Projects"] = "Progetti Recenti", -- src\editor\menu_file.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
|
||||
["Sel: %d/%d"] = "Sel: %d/%d", -- src\editor\editor.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
|
||||
["Set the project directory to be used"] = "Imposta la directory di progetto da usare", -- src\editor\menu_project.lua, src\editor\filetree.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
|
||||
["Show/Hide the status bar"] = "Mostra/Nascondi la barra di stato", -- src\editor\menu_view.lua
|
||||
["Show/Hide the toolbar"] = "Mostra/Nascondi la barra degli strumenti", -- src\editor\menu_view.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 debugging and continue running the process"] = "Ferma il debug e continua l'esecuzione del processo", -- 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 Bookmark"] = "Attiva/Disattiva Segnalibro", -- src\editor\menu_edit.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 +271,17 @@ 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
|
||||
["Zoom In"] = "Zoom In", -- src\editor\menu_view.lua
|
||||
["Zoom Out"] = "Zoom Out", -- src\editor\menu_view.lua
|
||||
["Zoom to 100%"] = "Zoom a 100%", -- src\editor\menu_view.lua
|
||||
["Zoom"] = "Zoom", -- src\editor\menu_view.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
|
||||
}
|
||||
|
||||
145
cfg/i18n/ru.lua
145
cfg/i18n/ru.lua
@@ -1,15 +1,20 @@
|
||||
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"] = "%s обработчик события вернул ошибку: %s", -- 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"] = "&Удалить", -- src\editor\filetree.lua
|
||||
["&Documentation"] = "Документация", -- src\editor\menu_help.lua
|
||||
["&Down"] = "Вниз", -- src\editor\findreplace.lua
|
||||
["&Edit Project Directory"] = "&Редактировать папку проекта", -- src\editor\filetree.lua
|
||||
["&Edit Watch"] = "&Редактировать выражение", -- src\editor\debugger.lua
|
||||
["&Edit"] = "&Правка", -- src\editor\menu_edit.lua
|
||||
["&File"] = "&Файл", -- src\editor\menu_file.lua
|
||||
@@ -17,76 +22,98 @@ return {
|
||||
["&Find Next"] = "Найти далее", -- src\editor\findreplace.lua
|
||||
["&Find"] = "&Найти", -- src\editor\menu_search.lua
|
||||
["&Fold/Unfold All"] = "Св&ернуть/развернуть все", -- src\editor\menu_edit.lua
|
||||
["&Goto Line"] = "&Перейти к строке", -- src\editor\menu_search.lua
|
||||
["&Frequently Asked Questions"] = "&Часто задаваемые вопросы", -- src\editor\menu_help.lua
|
||||
["&Getting Started Guide"] = nil, -- src\editor\menu_help.lua
|
||||
["&Go To Line..."] = "&Перейти к строке...", -- src\editor\menu_search.lua
|
||||
["&Help"] = "&Справка", -- src\editor\menu_help.lua
|
||||
["&New Directory"] = "&Новая папка", -- 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"] = "Страница проекта", -- 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"] = "Переименовать", -- 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
|
||||
["&Status Bar"] = "Панель состояния", -- src\editor\menu_view.lua
|
||||
["&Subdirectories"] = "В папках", -- src\editor\findreplace.lua
|
||||
["&Undo"] = "&Отменить", -- src\editor\editor.lua, src\editor\menu_edit.lua
|
||||
["&Tool Bar"] = "Панель инструментов", -- src\editor\menu_view.lua
|
||||
["&Tutorials"] = "&Обучающие материалы", -- 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
|
||||
["Bookmark"] = "Закладка", -- src\editor\menu_edit.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."] = "Невозможно запустить сервер отладки %s:%d: %s", -- 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
|
||||
["Can't stop debugger server as it is not started."] = "Невозможно остановить сервер отладки пока он не запущен", -- src\editor\debugger.lua
|
||||
["Cancel"] = "Отмена", -- 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
|
||||
["Cancelled by the user."] = "Отменено пользователем.", -- src\editor\findreplace.lua
|
||||
["Choose a project directory"] = "Выберите папку проекта", -- src\editor\findreplace.lua, src\editor\menu_project.lua, src\editor\gui.lua, src\editor\filetree.lua
|
||||
["Choose..."] = "Выбрать...", -- src\editor\menu_project.lua, src\editor\filetree.lua
|
||||
["Clear Items"] = "Очистить список", -- src\editor\menu_file.lua
|
||||
["Clear items from this list"] = "Удалить элементы из списка", -- src\editor\menu_file.lua
|
||||
["Clear the output window before compiling or debugging"] = "Очистить окно вывода перед компиляцией или отладкой", -- src\editor\menu_project.lua
|
||||
["Close &Other Pages"] = "Закрыть &остальные вкладки", -- src\editor\gui.lua
|
||||
["Close A&ll Pages"] = "Закрыть &все вкладки", -- src\editor\gui.lua
|
||||
["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'."] = "Рассмотрите вариант удаления backslash из строки '%s'.", -- src\editor\commands.lua
|
||||
["Copy Full Path"] = "Скопировать полный путь", -- 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
|
||||
["Debugger server stopped 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
|
||||
["Detach &Process"] = "Отсоединить процесс", -- src\editor\menu_project.lua
|
||||
["Directory"] = "Папка", -- src\editor\findreplace.lua
|
||||
["Do you want to delete '%s'?"] = "Удалить '%s'?", -- src\editor\filetree.lua
|
||||
["Do you want to overwrite it?"] = "Переписать его?", -- 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)"] = "Введите параметры командной строки (Cancel чтобы очистить)", -- 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 +129,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."] = "Файл уже существует.", -- 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,25 +148,30 @@ 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"] = "Перейти к определению", -- src\editor\editor.lua
|
||||
["Go To Line"] = "Перейти к строке", -- src\editor\menu_search.lua
|
||||
["Go To Next Bookmark"] = "Перейти к следующей закладке", -- src\editor\menu_edit.lua
|
||||
["Go To Previous Bookmark"] = "Перейти к предыдущей закладке", -- src\editor\menu_edit.lua
|
||||
["Go to a selected line"] = "Перейти к заданной строке", -- src\editor\menu_search.lua
|
||||
["Goto Line"] = "Перейти к строке", -- src\editor\menu_search.lua
|
||||
["INS"] = "ВСТ", -- src\editor\editor.lua
|
||||
["In Files"] = "Установки файлов", -- src\editor\findreplace.lua
|
||||
["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"] = "Новый файл", -- 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"] = "Открыть используя программу по умолчанию", -- 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
|
||||
@@ -149,68 +182,85 @@ return {
|
||||
["Program starting as '%s'."] = "Программа запускается как '%s'.", -- src\editor\output.lua
|
||||
["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 Directory"] = "Папка проекта", -- src\editor\menu_project.lua, src\editor\filetree.lua
|
||||
["Project history"] = "История проектов", -- src\editor\menu_file.lua
|
||||
["Project"] = "Проект", -- src\editor\gui.lua
|
||||
["Project/&FileTree Window"] = "Окно &проекта/списка файлов", -- src\editor\menu_view.lua
|
||||
["Provide command line parameters"] = "Установить параметры командной строки", -- 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
|
||||
["Recent &Projects"] = "Недавние &проекты", -- src\editor\menu_file.lua
|
||||
["Recent Files"] = "Недавние файлы", -- src\editor\menu_file.lua
|
||||
["Redo last edit undone"] = "Вернуть последнее отмененное изменение", -- src\editor\menu_edit.lua
|
||||
["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
|
||||
["Rename All Instances"] = "Переименовать все совпадения", -- 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
|
||||
["Replacing"] = "Замена", -- src\editor\findreplace.lua
|
||||
["Reset to default layout"] = "Установить расположение окон по умолчанию", -- src\editor\menu_view.lua
|
||||
["Resets the dynamic word list for autocompletion"] = "Очистить список динамических слов для автодополнения", -- src\editor\menu_edit.lua
|
||||
["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
|
||||
["Sel: %d/%d"] = "Выд: %d/%d", -- src\editor\editor.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"] = "Выделить слово под курсором и найти далее", -- src\editor\menu_search.lua
|
||||
["Select the word under cursor and find its previous occurrence"] = "Выделить слово под курсором и найти ранее", -- 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
|
||||
["Set the project directory to be used"] = "Установить используемую папку проекта", -- src\editor\menu_project.lua, src\editor\filetree.lua
|
||||
["Settings: System"] = "Установки: Системы", -- src\editor\menu_edit.lua
|
||||
["Settings: User"] = "Установки: Пользователя", -- src\editor\menu_edit.lua
|
||||
["Show &Tooltip"] = "Показать &подсказку", -- src\editor\menu_edit.lua
|
||||
["Show Location"] = "Показать файл в папке", -- 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
|
||||
["Show/Hide the status bar"] = "Показать/спрятать панель состояния", -- src\editor\menu_view.lua
|
||||
["Show/Hide the toolbar"] = "Показать/спрятать панель инструментов", -- src\editor\menu_view.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"] = "Начать или продолжить отладку", -- src\editor\gui.lua
|
||||
["Start or continue debugging"] = "Начать или продолжить отладку", -- 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 debugging and continue running the process"] = "Завершить отладку и продолжить текущий процесс", -- 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 Bookmark"] = "Установить/Снять закладку", -- src\editor\menu_edit.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'."] = "Ошибка создания папки '%s'.", -- src\editor\filetree.lua
|
||||
["Unable to create file '%s'."] = "Ошибка создания файла '%s'.", -- src\editor\filetree.lua
|
||||
["Unable to load file '%s'."] = "Ошибка загрузки файла '%s'.", -- src\editor\commands.lua
|
||||
["Unable to rename file '%s'."] = "Ошибка переименования файла '%s'.", -- 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 +271,17 @@ 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
|
||||
["Zoom In"] = "Приблизить", -- src\editor\menu_view.lua
|
||||
["Zoom Out"] = "Удалить", -- src\editor\menu_view.lua
|
||||
["Zoom to 100%"] = "Установить 100%", -- src\editor\menu_view.lua
|
||||
["Zoom"] = "Установить масштаб", -- src\editor\menu_view.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"] = "неизвестная ошибка", -- src\editor\debugger.lua
|
||||
}
|
||||
|
||||
@@ -1,29 +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')))
|
||||
- [SciTeLuaIDE](macro:shell(ApplyStyleConfig('cfg/tomorrow.lua','SciTeLuaIDE')))
|
||||
- [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
|
||||
|
||||
@@ -1,10 +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/
|
||||
-- Molokay colors based on https://github.com/tomasr/molokai/blob/master/colors/molokai.vim
|
||||
-- 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 = ...
|
||||
@@ -181,16 +181,16 @@ local colors = {
|
||||
NotepadPlusPlus = { -- contributed by Florian (https://github.com/SiENcE)
|
||||
Background = H'FFFFFF',
|
||||
CurrentLine = H'E9E2FF',
|
||||
Selection = H'ADADA1',
|
||||
Selection = H'C0C0C0',
|
||||
Foreground = H'000000',
|
||||
Comment = H'008000',
|
||||
Red = H'FF6900',
|
||||
Orange = H'00FF00',
|
||||
Orange = H'FF0000',
|
||||
Yellow = H'FF4E00',
|
||||
Green = H'808080',
|
||||
Aqua = H'260099',
|
||||
Aqua = H'000080',
|
||||
Blue = H'2123FF',
|
||||
Purple = H'FFFFFF',
|
||||
Purple = H'8000FF',
|
||||
},
|
||||
SciTeLuaIDE = { -- contributed by Jayanth Acharya
|
||||
Background = H'1B1D1E',
|
||||
@@ -260,7 +260,6 @@ return {
|
||||
calltip = nil,
|
||||
|
||||
-- common special (need custom fg & bg)
|
||||
calltipbg = nil,
|
||||
sel = {bg = C.Selection},
|
||||
caret = {fg = C.Foreground},
|
||||
caretlinebg = {bg = C.CurrentLine},
|
||||
@@ -269,7 +268,7 @@ return {
|
||||
edge = {},
|
||||
|
||||
indicator = {
|
||||
fncall = {fg = C.Purple, st = wxstc.wxSTC_INDIC_ROUNDBOX},
|
||||
fncall = {fg = C.Purple, st = wxstc.wxSTC_INDIC_HIDDEN},
|
||||
--[[ other possible values are:
|
||||
wxSTC_INDIC_PLAIN Single-line underline
|
||||
wxSTC_INDIC_SQUIGGLE Squiggly underline
|
||||
|
||||
@@ -9,7 +9,7 @@ See [configuration](http://studio.zerobrane.com/doc-configuration.html) page for
|
||||
|
||||
--]]--
|
||||
|
||||
-- an example of how loaded configuration can be modified from this file
|
||||
-- to modify loaded configuration for recognized extensions for lua files
|
||||
local G = ... -- this now points to the global environment in the script
|
||||
local luaspec = G.ide.specs['lua']
|
||||
luaspec.exts[#luaspec.exts+1] = "luaz"
|
||||
@@ -140,3 +140,16 @@ editor.nomousezoom = true
|
||||
-- you can also change it between runs from Local Console by executing
|
||||
-- `ide.config.corona = {skin = 'iPad'}`
|
||||
corona = { skin = "iPad" }
|
||||
|
||||
-- to style individual keywords; `return` and `break` are shown in red
|
||||
local G = ... -- this now points to the global environment in the script
|
||||
local luaspec = G.ide.specs.lua
|
||||
|
||||
local num = #luaspec.keywords
|
||||
-- take a new slot in the list of keywords (starting from 1)
|
||||
luaspec.keywords[num+1] = 'return break'
|
||||
-- remove 'return' from the list of "regular" keywords
|
||||
luaspec.keywords[1] = luaspec.keywords[1]:gsub(' return', ''):gsub(' break', '')
|
||||
|
||||
-- assign new style to the added slot (starting from 0)
|
||||
styles["keywords"..num] = {fg = {240, 0, 0}, b = true}
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
--[[-- Copy snippets from this file to `user.lua` --]]--
|
||||
|
||||
--[[ 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
|
||||
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 "eval", "Evaluate in Console\tCtrl-E")
|
||||
ide.frame:Connect(ID "eval", wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
function () ShellExecuteCode(GetEditor():GetSelectedText()) end)
|
||||
ide.frame:Connect(ID "eval", wx.wxEVT_UPDATE_UI,
|
||||
function (event) event:Enable(GetEditor() and #GetEditor():GetSelectedText() > 0) 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']
|
||||
|
||||
local num = #luaspec.keywords
|
||||
-- take a new slot in the list of keywords (starting from 1)
|
||||
luaspec.keywords[num+1] = 'return'
|
||||
-- remove 'return' from the list of "regular" keywords
|
||||
luaspec.keywords[1] = luaspec.keywords[1]:gsub(' return', '')
|
||||
|
||||
-- assign new style to the added slot (starting from 0)
|
||||
styles["keywords"..num] = {fg = {240, 0, 0}, b = true}
|
||||
--]]
|
||||
@@ -53,7 +53,7 @@ return {
|
||||
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)
|
||||
function() if rundebug then wx.wxRemoveFile(file) end end)
|
||||
end,
|
||||
fprojdir = function(self,wfilename)
|
||||
return wfilename:GetPath(wx.wxPATH_GET_VOLUME)
|
||||
|
||||
@@ -13,10 +13,8 @@ return {
|
||||
if not corona then
|
||||
local sep = win and ';' or ':'
|
||||
local default =
|
||||
win and ([[C:\Program Files\Corona SDK]]..sep..[[D:\Program Files\Corona SDK]]..sep..
|
||||
[[C:\Program Files\Corona Labs\Corona SDK]]..sep..[[D:\Program Files\Corona Labs\Corona SDK]]..sep..
|
||||
[[C:\Program Files (x86)\Corona SDK]]..sep..[[D:\Program Files (x86)\Corona SDK]]..sep..
|
||||
[[C:\Program Files (x86)\Corona Labs\Corona SDK]]..sep..[[D:\Program Files (x86)\Corona Labs\Corona SDK]]..sep)
|
||||
win and (GenerateProgramFilesPath('Corona SDK', sep)..sep..
|
||||
GenerateProgramFilesPath('Corona Labs\\Corona SDK', sep)..sep)
|
||||
or mac and ('/Applications/CoronaSDK/Corona Simulator.app/Contents/MacOS'..sep)
|
||||
or ''
|
||||
local path = default
|
||||
@@ -56,12 +54,13 @@ return {
|
||||
or MergeFullPath(GetPathWithSep(corona), "Resources/mobdebug.lua")
|
||||
local mdbl = MergeFullPath(GetPathWithSep(ide.editorFilename), "lualibs/mobdebug/mobdebug.lua")
|
||||
local needed = needRefresh(mdbl, mdbc)
|
||||
local mdbcplugin = win and MergeFullPath(wx.wxStandardPaths.Get():GetUserLocalDataDir(),
|
||||
"../../Roaming/Corona Labs/Corona Simulator/Plugins/mobdebug.lua")
|
||||
if needed then
|
||||
local copied = FileCopy(mdbl, mdbc)
|
||||
-- couldn't copy to the Resources/ folder; not have permissions?
|
||||
if not copied and win then
|
||||
mdbc = MergeFullPath(wx.wxStandardPaths.Get():GetUserLocalDataDir(),
|
||||
"../../Roaming/Corona Labs/Corona Simulator/Plugins/mobdebug.lua")
|
||||
mdbc = mdbcplugin
|
||||
needed = needRefresh(mdbl, mdbc)
|
||||
copied = needed and FileCopy(mdbl, mdbc)
|
||||
end
|
||||
@@ -74,6 +73,10 @@ return {
|
||||
if not copied then return end
|
||||
end
|
||||
end
|
||||
-- remove debugger if copied to plugin directory as it may be obsolete
|
||||
if mdbcplugin and mdbcplugin ~= mdbc and wx.wxFileExists(mdbcplugin) then
|
||||
wx.wxRemoveFile(mdbcplugin)
|
||||
end
|
||||
end
|
||||
|
||||
local debugopt = mac and "-debug 1 -project " or "-debug "
|
||||
@@ -82,8 +85,7 @@ return {
|
||||
local cmd = ('"%s" %s"%s"%s')
|
||||
:format(corona, rundebug and debugopt or "", file, skin)
|
||||
-- CommandLineRun(cmd,wdir,tooutput,nohide,stringcallback,uid,endcallback)
|
||||
return CommandLineRun(cmd,self:fworkdir(wfilename),true,false,nil,nil,
|
||||
function() ide.debugger.pid = nil end)
|
||||
return CommandLineRun(cmd,self:fworkdir(wfilename),true,false)
|
||||
end,
|
||||
fprojdir = function(self,wfilename)
|
||||
return wfilename:GetPath(wx.wxPATH_GET_VOLUME)
|
||||
|
||||
@@ -29,8 +29,7 @@ return {
|
||||
if not gideros then
|
||||
local sep = win and ';' or ':'
|
||||
local default =
|
||||
win and ([[C:\Program Files\Gideros]]..sep..[[D:\Program Files\Gideros]]..sep..
|
||||
[[C:\Program Files (x86)\Gideros]]..sep..[[D:\Program Files (x86)\Gideros]]..sep)
|
||||
win and (GenerateProgramFilesPath('Gideros', sep)..sep)
|
||||
or mac and ('/Applications/Gideros Studio/Gideros Player.app/Contents/MacOS'..sep)
|
||||
or ''
|
||||
local path = default
|
||||
@@ -90,15 +89,14 @@ return {
|
||||
else
|
||||
local cmd = ('"%s"'):format(gideros)
|
||||
-- CommandLineRun(cmd,wdir,tooutput,nohide,stringcallback,uid,endcallback)
|
||||
pid = CommandLineRun(cmd,self:fworkdir(wfilename),not mac,true,nil,nil,
|
||||
function() ide.debugger.pid = nil end)
|
||||
pid = CommandLineRun(cmd,self:fworkdir(wfilename),not mac,true)
|
||||
if not pid then return end
|
||||
end
|
||||
|
||||
do
|
||||
DisplayOutputLn("Starting the player and waiting for the bridge to connect at '"..gdrbridge.."'.")
|
||||
local cmd = ('"%s" %s'):format(gdrbridge, 'isconnected')
|
||||
local attempts, connected = 12
|
||||
local attempts, connected = 15
|
||||
for _ = 1, attempts do
|
||||
local proc = wx.wxProcess()
|
||||
proc:Redirect()
|
||||
@@ -107,7 +105,7 @@ return {
|
||||
if not isValidPid(bid, cmd) then return end
|
||||
|
||||
local streamin = proc:GetInputStream()
|
||||
for _ = 1, 20 do
|
||||
for _ = 1, 30 do
|
||||
if streamin:CanRead() then
|
||||
connected = tonumber(streamin:Read(4096)) == 1
|
||||
break end
|
||||
|
||||
@@ -11,10 +11,7 @@ return {
|
||||
gslshell = gslshell or ide.config.path.gslshell -- check if the path is configured
|
||||
if not gslshell then
|
||||
local sep = win and ';' or ':'
|
||||
local default =
|
||||
win and ([[C:\Program Files\gsl-shell]]..sep..[[D:\Program Files\gsl-shell]]..sep..
|
||||
[[C:\Program Files (x86)\gsl-shell]]..sep..[[D:\Program Files (x86)\gsl-shell]]..sep)
|
||||
or ''
|
||||
local default = win and GenerateProgramFilesPath('gsl-shell', sep)..sep or ''
|
||||
local path = default
|
||||
..(os.getenv('PATH') or '')..sep
|
||||
..(GetPathWithSep(self:fworkdir(wfilename)))..sep
|
||||
@@ -51,18 +48,38 @@ return {
|
||||
end
|
||||
end
|
||||
|
||||
local filepath = wfilename:GetFullPath()
|
||||
if rundebug then
|
||||
DebuggerAttachDefault({runstart = ide.config.debugger.runonstart == true})
|
||||
end
|
||||
|
||||
local code = rundebug
|
||||
and ([[-e "io.stdout:setvbuf('no'); %s"]]):format(rundebug)
|
||||
or ([[-e "io.stdout:setvbuf('no')" "%s"]]):format(wfilename:GetFullPath())
|
||||
local cmd = '"'..gslshell..'" '..code
|
||||
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() if rundebug then wx.wxRemoveFile(filepath) end end)
|
||||
end,
|
||||
fprojdir = function(self,wfilename)
|
||||
return wfilename:GetPath(wx.wxPATH_GET_VOLUME)
|
||||
@@ -75,4 +92,5 @@ return {
|
||||
skipcompile = true,
|
||||
unhideanywindow = true,
|
||||
scratchextloop = false,
|
||||
takeparameters = true,
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -43,8 +46,7 @@ return {
|
||||
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)
|
||||
local pid = CommandLineRun(cmd,self:fworkdir(wfilename),true,false)
|
||||
|
||||
-- restore PATH
|
||||
wx.wxSetEnv("PATH", path)
|
||||
@@ -54,7 +56,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,
|
||||
|
||||
@@ -13,8 +13,7 @@ return {
|
||||
if not love2d then
|
||||
local sep = win and ';' or ':'
|
||||
local default =
|
||||
win and ([[C:\Program Files\love]]..sep..[[D:\Program Files\love]]..sep..
|
||||
[[C:\Program Files (x86)\love]]..sep..[[D:\Program Files (x86)\love]]..sep)
|
||||
win and (GenerateProgramFilesPath('love', sep)..sep)
|
||||
or mac and ('/Applications/love.app/Contents/MacOS'..sep)
|
||||
or ''
|
||||
local path = default
|
||||
@@ -42,11 +41,11 @@ 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)
|
||||
return CommandLineRun(cmd,self:fworkdir(wfilename),true,true)
|
||||
end,
|
||||
fprojdir = function(self,wfilename)
|
||||
return wfilename:GetPath(wx.wxPATH_GET_VOLUME)
|
||||
@@ -57,4 +56,5 @@ return {
|
||||
hasdebugger = true,
|
||||
fattachdebug = function(self) DebuggerAttachDefault() end,
|
||||
scratchextloop = true,
|
||||
takeparameters = true,
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
function MakeLuaInterpreter(version, name)
|
||||
|
||||
local exe
|
||||
|
||||
local function exePath(self, version)
|
||||
local version = tostring(version):gsub('%.','')
|
||||
local mainpath = ide.editorFilename:gsub("[^/\\]+$","")
|
||||
@@ -19,10 +17,24 @@ return {
|
||||
luaversion = version or '5.1',
|
||||
fexepath = exePath,
|
||||
frun = function(self,wfilename,rundebug)
|
||||
exe = exe or self:fexepath(version or "")
|
||||
local exe = self:fexepath(version or "")
|
||||
local filepath = wfilename:GetFullPath()
|
||||
if rundebug then
|
||||
DebuggerAttachDefault({runstart = ide.config.debugger.runonstart == true})
|
||||
|
||||
-- update arg to point to the proper file
|
||||
rundebug = ('if arg then arg[0] = [[%s]] end '):format(filepath)..rundebug
|
||||
|
||||
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
|
||||
@@ -34,22 +46,26 @@ 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 rundebug and cpath then
|
||||
wx.wxSetEnv("LUA_CPATH", ide.osclibs..';'..cpath)
|
||||
end
|
||||
if version and cpath and not cpath:find(clibs, 1, true) then
|
||||
wx.wxSetEnv("LUA_CPATH", cpath:gsub('/clibs/', clibs)) end
|
||||
local _, cpath = wx.wxGetEnv("LUA_CPATH")
|
||||
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() if rundebug then wx.wxRemoveFile(filepath) end end)
|
||||
|
||||
if version and cpath then wx.wxSetEnv("LUA_CPATH", cpath) end
|
||||
if (rundebug or version) and cpath then wx.wxSetEnv("LUA_CPATH", cpath) end
|
||||
return pid
|
||||
end,
|
||||
fprojdir = function(self,wfilename)
|
||||
@@ -62,6 +78,7 @@ return {
|
||||
fattachdebug = function(self) DebuggerAttachDefault() end,
|
||||
scratchextloop = false,
|
||||
unhideanywindow = true,
|
||||
takeparameters = true,
|
||||
}
|
||||
|
||||
end
|
||||
|
||||
@@ -2,94 +2,74 @@
|
||||
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 "")
|
||||
|
||||
local pid, proc
|
||||
if (CommandLineRunning(self:fuid(wfilename))) then
|
||||
-- kill process
|
||||
wx.wxProcess.Kill(pid)
|
||||
end
|
||||
|
||||
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({
|
||||
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
|
||||
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
|
||||
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
|
||||
|
||||
return pid
|
||||
args = args..(rundebug
|
||||
and ([[ -e "%s"]]):format(rundebug)
|
||||
or ([[ "%s"]]):format(filename))
|
||||
|
||||
local cmd = '"'..exe..'" '..args
|
||||
|
||||
return CommandLineRun(cmd,wdir,true,true,nil,self:fuid(wfilename))
|
||||
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,
|
||||
}
|
||||
|
||||
@@ -16,8 +16,7 @@ return {
|
||||
local sep = win and ';' or ':'
|
||||
local path =
|
||||
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)
|
||||
GenerateProgramFilesPath('Marmalade', sep)..sep)
|
||||
or mac and ([[/Applications/Marmalade.app/Contents]]..sep..
|
||||
[[/Developer/Marmalade]]..sep)
|
||||
or ''
|
||||
@@ -113,8 +112,7 @@ return {
|
||||
|
||||
local cmd = ('"%s" %s'):format(quick, options)
|
||||
-- CommandLineRun(cmd,wdir,tooutput,nohide,stringcallback,uid,endcallback)
|
||||
return CommandLineRun(cmd,GetPathWithSep(projdir),true,true,nil,nil,
|
||||
function() ide.debugger.pid = nil end)
|
||||
return CommandLineRun(cmd,GetPathWithSep(projdir),true,true)
|
||||
end,
|
||||
fprojdir = function(self,wfilename)
|
||||
return wfilename:GetPath(wx.wxPATH_GET_VOLUME)
|
||||
|
||||
@@ -11,10 +11,7 @@ return {
|
||||
moai = moai or ide.config.path.moai -- check if the path is configured
|
||||
if not moai then
|
||||
local sep = win and ';' or ':'
|
||||
local default =
|
||||
win and ([[C:\Program Files\moai]]..sep..[[D:\Program Files\moai]]..sep..
|
||||
[[C:\Program Files (x86)\moai]]..sep..[[D:\Program Files (x86)\moai]]..sep)
|
||||
or ''
|
||||
local default = win and GenerateProgramFilesPath('moai', sep)..sep or ''
|
||||
local path = default
|
||||
..(os.getenv('PATH') or '')..sep
|
||||
..(os.getenv('MOAI_BIN') or '')..sep
|
||||
@@ -87,7 +84,7 @@ return {
|
||||
or ('"%s" "%s"'):format(moai, file)
|
||||
-- CommandLineRun(cmd,wdir,tooutput,nohide,stringcallback,uid,endcallback)
|
||||
return CommandLineRun(cmd,self:fworkdir(wfilename),true,false,nil,nil,
|
||||
function() ide.debugger.pid = nil if rundebug then wx.wxRemoveFile(file) end end)
|
||||
function() if rundebug then wx.wxRemoveFile(file) end end)
|
||||
end,
|
||||
fprojdir = function(self,wfilename)
|
||||
return wfilename:GetPath(wx.wxPATH_GET_VOLUME)
|
||||
|
||||
@@ -18,7 +18,7 @@ if package.loaded["socket.http"] then
|
||||
end
|
||||
|
||||
local socket = require "socket"
|
||||
|
||||
local gettime = socket.gettime
|
||||
local coxpcall = require "coxpcall"
|
||||
|
||||
local WATCH_DOG_TIMEOUT = 120
|
||||
@@ -60,7 +60,7 @@ local copas = {}
|
||||
-- Meta information is public even if beginning with an "_"
|
||||
copas._COPYRIGHT = "Copyright (C) 2005-2010 Kepler Project"
|
||||
copas._DESCRIPTION = "Coroutine Oriented Portable Asynchronous Services"
|
||||
copas._VERSION = "Copas 1.1.7"
|
||||
copas._VERSION = "Copas 1.2.1"
|
||||
|
||||
-- Close the socket associated with the current connection after the handler finishes
|
||||
copas.autoclose = true
|
||||
@@ -117,6 +117,65 @@ local function newset()
|
||||
return set
|
||||
end
|
||||
|
||||
local fnil = function()end
|
||||
local _sleeping = {
|
||||
times = {}, -- list with wake-up times
|
||||
cos = {}, -- list with coroutines, index matches the 'times' list
|
||||
lethargy = {}, -- list of coroutines sleeping without a wakeup time
|
||||
|
||||
insert = fnil,
|
||||
remove = fnil,
|
||||
push = function(self, sleeptime, co)
|
||||
if not co then return end
|
||||
if sleeptime<0 then
|
||||
--sleep until explicit wakeup through copas.wakeup
|
||||
self.lethargy[co] = true
|
||||
return
|
||||
else
|
||||
sleeptime = gettime() + sleeptime
|
||||
end
|
||||
local t, c = self.times, self.cos
|
||||
local i, cou = 1, #t
|
||||
--TODO: do a binary search
|
||||
while i<=cou and t[i]<=sleeptime do i=i+1 end
|
||||
table.insert(t, i, sleeptime)
|
||||
table.insert(c, i, co)
|
||||
end,
|
||||
getnext = function(self) -- returns delay until next sleep expires, or nil if there is none
|
||||
local t = self.times
|
||||
local delay = t[1] and t[1] - gettime() or nil
|
||||
|
||||
return delay and math.max(delay, 0) or nil
|
||||
end,
|
||||
-- find the thread that should wake up to the time
|
||||
pop = function(self, time)
|
||||
local t, c = self.times, self.cos
|
||||
if #t==0 or time<t[1] then return end
|
||||
local co = c[1]
|
||||
table.remove(t, 1)
|
||||
table.remove(c, 1)
|
||||
return co
|
||||
end,
|
||||
wakeup = function(self, co)
|
||||
local let = self.lethargy
|
||||
if let[co] then
|
||||
self:push(0, co)
|
||||
let[co] = nil
|
||||
else
|
||||
let = self.cos
|
||||
for i=1,#let do
|
||||
if let[i]==co then
|
||||
table.remove(let, i)
|
||||
local tm = self.times[i]
|
||||
table.remove(self.times, i)
|
||||
self:push(0, co)
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
} --_sleeping
|
||||
|
||||
local _servers = newset() -- servers being handled
|
||||
local _reading_log = {}
|
||||
local _writing_log = {}
|
||||
@@ -140,7 +199,7 @@ function copas.receive(client, pattern, part)
|
||||
_reading_log[client] = nil
|
||||
return s, err, part
|
||||
end
|
||||
_reading_log[client] = os.time()
|
||||
_reading_log[client] = gettime()
|
||||
coroutine.yield(client, _reading)
|
||||
until false
|
||||
end
|
||||
@@ -156,26 +215,26 @@ function copas.receivefrom(client, size)
|
||||
_reading_log[client] = nil
|
||||
return s, err, port
|
||||
end
|
||||
_reading_log[client] = os.time()
|
||||
_reading_log[client] = gettime()
|
||||
coroutine.yield(client, _reading)
|
||||
until false
|
||||
end
|
||||
|
||||
-- same as above but with special treatment when reading chunks,
|
||||
-- unblocks on any data received.
|
||||
function copas.receivePartial(client, pattern)
|
||||
local s, err, part
|
||||
function copas.receivePartial(client, pattern, part)
|
||||
local s, err
|
||||
pattern = pattern or "*l"
|
||||
repeat
|
||||
s, err, part = client:receive(pattern)
|
||||
s, err, part = client:receive(pattern, part)
|
||||
if s or ( (type(pattern)=="number") and part~="" and part ~=nil ) or
|
||||
err ~= "timeout" then
|
||||
_reading_log[client] = nil
|
||||
return s, err, part
|
||||
end
|
||||
_reading_log[client] = os.time()
|
||||
coroutine.yield(client, _reading)
|
||||
until false
|
||||
err ~= "timeout" then
|
||||
_reading_log[client] = nil
|
||||
return s, err, part
|
||||
end
|
||||
_reading_log[client] = gettime()
|
||||
coroutine.yield(client, _reading)
|
||||
until false
|
||||
end
|
||||
|
||||
-- sends data to a client. The operation is buffered and
|
||||
@@ -191,14 +250,14 @@ function copas.send(client, data, from, to)
|
||||
-- adds extra corrotine swap
|
||||
-- garantees that high throuput dont take other threads to starvation
|
||||
if (math.random(100) > 90) then
|
||||
_writing_log[client] = os.time()
|
||||
_writing_log[client] = gettime()
|
||||
coroutine.yield(client, _writing)
|
||||
end
|
||||
if s or err ~= "timeout" then
|
||||
_writing_log[client] = nil
|
||||
return s, err,lastIndex
|
||||
end
|
||||
_writing_log[client] = os.time()
|
||||
_writing_log[client] = gettime()
|
||||
coroutine.yield(client, _writing)
|
||||
until false
|
||||
end
|
||||
@@ -213,14 +272,14 @@ function copas.sendto(client, data, ip, port)
|
||||
-- adds extra corrotine swap
|
||||
-- garantees that high throuput dont take other threads to starvation
|
||||
if (math.random(100) > 90) then
|
||||
_writing_log[client] = os.time()
|
||||
_writing_log[client] = gettime()
|
||||
coroutine.yield(client, _writing)
|
||||
end
|
||||
if s or err ~= "timeout" then
|
||||
_writing_log[client] = nil
|
||||
return s, err
|
||||
end
|
||||
_writing_log[client] = os.time()
|
||||
_writing_log[client] = gettime()
|
||||
coroutine.yield(client, _writing)
|
||||
until false
|
||||
end
|
||||
@@ -235,7 +294,7 @@ function copas.connect(skt, host, port)
|
||||
_writing_log[skt] = nil
|
||||
return ret, err
|
||||
end
|
||||
_writing_log[skt] = os.time()
|
||||
_writing_log[skt] = gettime()
|
||||
coroutine.yield(skt, _writing)
|
||||
until false
|
||||
return ret, err
|
||||
@@ -251,11 +310,11 @@ local _skt_mt = {__index = {
|
||||
return copas.send (self.socket, data, from, to)
|
||||
end,
|
||||
|
||||
receive = function (self, pattern)
|
||||
receive = function (self, pattern, prefix)
|
||||
if (self.timeout==0) then
|
||||
return copas.receivePartial(self.socket, pattern)
|
||||
return copas.receivePartial(self.socket, pattern, prefix)
|
||||
end
|
||||
return copas.receive(self.socket, pattern)
|
||||
return copas.receive(self.socket, pattern, prefix)
|
||||
end,
|
||||
|
||||
flush = function (self)
|
||||
@@ -264,8 +323,12 @@ local _skt_mt = {__index = {
|
||||
|
||||
settimeout = function (self,time)
|
||||
self.timeout=time
|
||||
return
|
||||
return true
|
||||
end,
|
||||
|
||||
skip = function(self, ...) return self.socket:skip(...) end,
|
||||
|
||||
close = function(self, ...) return self.socket:close(...) end,
|
||||
}}
|
||||
|
||||
-- wraps a UDP socket, copy of TCP one adapted for UDP.
|
||||
@@ -293,7 +356,7 @@ local _skt_mt_udp = {__index = {
|
||||
|
||||
settimeout = function (self,time)
|
||||
self.timeout=time
|
||||
return
|
||||
return true
|
||||
end,
|
||||
}}
|
||||
|
||||
@@ -385,6 +448,13 @@ function copas.addserver(server, handler, timeout)
|
||||
addTCPserver(server, handler, timeout)
|
||||
end
|
||||
end
|
||||
|
||||
function copas.removeserver(server)
|
||||
_servers[server] = nil
|
||||
_reading:remove(server)
|
||||
return server:close()
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Adds an new courotine thread to Copas dispatcher
|
||||
-------------------------------------------------------------------------------
|
||||
@@ -464,6 +534,24 @@ local _writable_t = {
|
||||
}
|
||||
|
||||
addtaskWrite (_writable_t)
|
||||
--
|
||||
--sleeping threads task
|
||||
local _sleeping_t = {
|
||||
tick = function (self, time, ...)
|
||||
_doTick(_sleeping:pop(time), ...)
|
||||
end
|
||||
}
|
||||
|
||||
-- yields the current coroutine and wakes it after 'sleeptime' seconds.
|
||||
-- If sleeptime<0 then it sleeps until explicitly woken up using 'wakeup'
|
||||
function copas.sleep(sleeptime)
|
||||
coroutine.yield((sleeptime or 0), _sleeping)
|
||||
end
|
||||
|
||||
-- Wakes up a sleeping coroutine 'co'.
|
||||
function copas.wakeup(co)
|
||||
_sleeping:wakeup(co)
|
||||
end
|
||||
|
||||
local last_cleansing = 0
|
||||
|
||||
@@ -472,8 +560,8 @@ local last_cleansing = 0
|
||||
-------------------------------------------------------------------------------
|
||||
local function _select (timeout)
|
||||
local err
|
||||
local now = os.time()
|
||||
local duration = os.difftime
|
||||
local now = gettime()
|
||||
local duration = function(t2, t1) return t2-t1 end
|
||||
|
||||
_readable_t._evs, _writable_t._evs, err = socket.select(_reading, _writing, timeout)
|
||||
local r_evs, w_evs = _readable_t._evs, _writable_t._evs
|
||||
@@ -512,6 +600,14 @@ end
|
||||
-- handled (or nil + error message)
|
||||
-------------------------------------------------------------------------------
|
||||
function copas.step(timeout)
|
||||
_sleeping_t:tick(gettime())
|
||||
|
||||
-- Need to wake up the select call it time for the next sleeping event
|
||||
local nextwait = _sleeping:getnext()
|
||||
if nextwait then
|
||||
timeout = timeout and math.min(nextwait, timeout) or nextwait
|
||||
end
|
||||
|
||||
local err = _select (timeout)
|
||||
if err == "timeout" then return false end
|
||||
|
||||
@@ -537,4 +633,4 @@ function copas.loop(timeout)
|
||||
end
|
||||
end
|
||||
|
||||
return copas
|
||||
return copas
|
||||
|
||||
@@ -23,20 +23,7 @@
|
||||
|
||||
--! require 'luainspect.typecheck' (context)
|
||||
|
||||
-- boilerplate/utility
|
||||
-- LUA_PATH="?.lua;/path/to/metalua/src/compiler/?.lua;/path/to/metalua/src/lib/?.lua"
|
||||
-- import modules -- order is important
|
||||
require "lexer"
|
||||
require "gg"
|
||||
require "mlp_lexer"
|
||||
require "mlp_misc"
|
||||
require "mlp_table"
|
||||
require "mlp_meta"
|
||||
require "mlp_expr"
|
||||
require "mlp_stat"
|
||||
--require "mlp_ext"
|
||||
_G.mlc = {} -- make gg happy
|
||||
-- Metalua:IMPROVE: make above imports simpler
|
||||
local mlc = require 'metalua.compiler'.new()
|
||||
|
||||
local M = {}
|
||||
|
||||
@@ -102,10 +89,7 @@ end
|
||||
-- FIX? filename currently ignored in Metalua
|
||||
-- CATEGORY: Lua parsing
|
||||
local function ast_from_string_helper(src, filename)
|
||||
filename = filename or '(string)'
|
||||
local lx = mlp.lexer:newstream (src, filename)
|
||||
local ast = mlp.chunk(lx)
|
||||
return ast
|
||||
return mlc:src_to_ast(src, filename)
|
||||
end
|
||||
|
||||
|
||||
@@ -370,7 +354,7 @@ function M.get_keywords(ast, src)
|
||||
-- Some binary operations have arguments reversed from lexical order.
|
||||
-- For example, `a > b` becomes `Op{'lt', `Id 'b', `Id 'a'}
|
||||
local oast =
|
||||
(ast.tag == 'Op' and #ast == 3 and ast[2].lineinfo.first[3] > ast[3].lineinfo.first[3])
|
||||
(ast.tag == 'Op' and #ast == 3 and tostring(ast[2].lineinfo.first):match('|L(%d+)') > tostring(ast[3].lineinfo.first):match('|L(%d+)'))
|
||||
and {ast[1], ast[3], ast[2]} or ast
|
||||
|
||||
local i = 0
|
||||
@@ -381,18 +365,17 @@ function M.get_keywords(ast, src)
|
||||
-- Get position range [fpos,lpos] between subsequent children.
|
||||
local fpos
|
||||
if i == 0 then -- before first child
|
||||
fpos = ast.lineinfo.first[3]
|
||||
fpos = tostring(ast.lineinfo.first):match('|L(%d+)')
|
||||
else
|
||||
local last = oast[i].lineinfo.last; local c = last.comments
|
||||
fpos = (c and #c > 0 and c[#c][3] or last[3]) + 1
|
||||
fpos = (c and #c > 0 and c[#c][3] or tostring(last):match('|L(%d+)')) + 1
|
||||
end
|
||||
local lpos
|
||||
if j == #ast+1 then -- after last child
|
||||
lpos = ast.lineinfo.last[3]
|
||||
lpos = tostring(ast.lineinfo.last):match('|L(%d+)')
|
||||
else
|
||||
local first = oast[j].lineinfo.first; local c = first.comments
|
||||
--DEBUG('first', ast.tag, first[3], src:sub(first[3], first[3]+3))
|
||||
lpos = (c and #c > 0 and c[1][2] or first[3]) - 1
|
||||
lpos = (c and #c > 0 and c[1][2] or tostring(first):match('|L(%d+)')) - 1
|
||||
end
|
||||
|
||||
-- Find keyword in range.
|
||||
@@ -441,7 +424,7 @@ function M.ast_to_tokenlist(top_ast, src)
|
||||
if isterminal[ast.tag] then -- Extract terminal
|
||||
local token = ast
|
||||
if ast.lineinfo then
|
||||
token.fpos, token.lpos, token.ast = ast.lineinfo.first[3], ast.lineinfo.last[3], ast
|
||||
token.fpos, token.lpos, token.ast = tostring(ast.lineinfo.first):match('|L(%d+)'), tostring(ast.lineinfo.last):match('|L(%d+)'), ast
|
||||
table.insert(tokens, token)
|
||||
end
|
||||
else -- Extract non-terminal
|
||||
|
||||
@@ -770,7 +770,7 @@ function M.infer_values(top_ast, tokenlist, src, report)
|
||||
end
|
||||
-- Any call to require is handled specially (source analysis).
|
||||
if func == require and type(argvalues[1]) == 'string' then
|
||||
local spath = ast.lineinfo.first[4] -- a HACK? relies on AST lineinfo
|
||||
local spath = tostring(ast.lineinfo.first):gsub('<C|','<'):match('<([^|]+)') -- a HACK? relies on AST lineinfo
|
||||
local val = M.require_inspect(argvalues[1], report, spath:gsub('[^\\/]+$', ''))
|
||||
if known(val) and val ~= nil then
|
||||
ast.value = val
|
||||
@@ -820,7 +820,7 @@ function M.infer_values(top_ast, tokenlist, src, report)
|
||||
local x
|
||||
local val = function() x=nil end
|
||||
local fpos = LA.ast_pos_range(ast, tokenlist)
|
||||
local source = ast.lineinfo.first[4] -- a HACK? relies on AST lineinfo
|
||||
local source = tostring(ast.lineinfo.first):gsub('<C|','<'):match('<([^|]+)') -- a HACK? relies on AST lineinfo
|
||||
local linenum = LA.pos_to_linecol(fpos, src)
|
||||
local retvals
|
||||
if ENABLE_RETURN_ANALYSIS then
|
||||
@@ -1269,7 +1269,7 @@ function M.ast_to_definition_position(ast, tokenlist)
|
||||
if local_ast then
|
||||
local tidx = LA.ast_idx_range_in_tokenlist(tokenlist, local_ast)
|
||||
if tidx then
|
||||
local spath = ast.lineinfo.first[4] -- a HACK? using lineinfo
|
||||
local spath = tostring(ast.lineinfo.first):gsub('<C|','<'):match('<([^|]+)') -- a HACK? using lineinfo
|
||||
fpos = tokenlist[tidx].fpos; path = spath
|
||||
end
|
||||
end
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
162
lualibs/metalua/compiler.lua
Normal file
162
lualibs/metalua/compiler.lua
Normal file
@@ -0,0 +1,162 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- Copyright (c) 2006-2013 Fabien Fleutot and others.
|
||||
--
|
||||
-- All rights reserved.
|
||||
--
|
||||
-- This program and the accompanying materials are made available
|
||||
-- under the terms of the Eclipse Public License v1.0 which
|
||||
-- accompanies this distribution, and is available at
|
||||
-- http://www.eclipse.org/legal/epl-v10.html
|
||||
--
|
||||
-- This program and the accompanying materials are also made available
|
||||
-- under the terms of the MIT public license which accompanies this
|
||||
-- distribution, and is available at http://www.lua.org/license.html
|
||||
--
|
||||
-- Contributors:
|
||||
-- Fabien Fleutot - API and implementation
|
||||
--
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
--
|
||||
-- Convert between various code representation formats. Atomic
|
||||
-- converters are written in extenso, others are composed automatically
|
||||
-- by chaining the atomic ones together in a closure.
|
||||
--
|
||||
-- Supported formats are:
|
||||
--
|
||||
-- * srcfile: the name of a file containing sources.
|
||||
-- * src: these sources as a single string.
|
||||
-- * lexstream: a stream of lexemes.
|
||||
-- * ast: an abstract syntax tree.
|
||||
-- * proto: a (Yueliang) struture containing a high level
|
||||
-- representation of bytecode. Largely based on the
|
||||
-- Proto structure in Lua's VM
|
||||
-- * bytecode: a string dump of the function, as taken by
|
||||
-- loadstring() and produced by string.dump().
|
||||
-- * function: an executable lua function in RAM.
|
||||
--
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
require 'checks'
|
||||
|
||||
local M = { }
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Order of the transformations. if 'a' is on the left of 'b', then a 'a' can
|
||||
-- be transformed into a 'b' (but not the other way around).
|
||||
-- M.sequence goes for numbers to format names, M.order goes from format
|
||||
-- names to numbers.
|
||||
--------------------------------------------------------------------------------
|
||||
M.sequence = {
|
||||
'srcfile', 'src', 'lexstream', 'ast', 'proto', 'bytecode', 'function' }
|
||||
|
||||
local arg_types = {
|
||||
srcfile = { 'string', '?string' },
|
||||
src = { 'string', '?string' },
|
||||
lexstream = { 'lexer.stream', '?string' },
|
||||
ast = { 'table', '?string' },
|
||||
proto = { 'table', '?string' },
|
||||
bytecode = { 'string', '?string' },
|
||||
}
|
||||
|
||||
M.order= { }; for a,b in pairs(M.sequence) do M.order[b]=a end
|
||||
|
||||
local CONV = { } -- conversion metatable __index
|
||||
|
||||
function CONV :srcfile_to_src(x, name)
|
||||
checks('metalua.compiler', 'string', '?string')
|
||||
name = name or '@'..x
|
||||
local f, msg = io.open (x, 'rb')
|
||||
if not f then error(msg) end
|
||||
local r, msg = f :read '*a'
|
||||
if not r then error("Cannot read file '"..x.."': "..msg) end
|
||||
f :close()
|
||||
return r, name
|
||||
end
|
||||
|
||||
function CONV :src_to_lexstream(src, name)
|
||||
checks('metalua.compiler', 'string', '?string')
|
||||
local r = self.parser.lexer :newstream (src, name)
|
||||
return r, name
|
||||
end
|
||||
|
||||
function CONV :lexstream_to_ast(lx, name)
|
||||
checks('metalua.compiler', 'lexer.stream', '?string')
|
||||
local r = self.parser.chunk(lx)
|
||||
r.source = name
|
||||
return r, name
|
||||
end
|
||||
|
||||
local bytecode_compiler = nil -- cache to avoid repeated `pcall(require(...))`
|
||||
local function get_bytecode_compiler()
|
||||
if bytecode_compiler then return bytecode_compiler else
|
||||
local status, result = pcall(require, 'metalua.compiler.bytecode')
|
||||
if status then
|
||||
bytecode_compiler = result
|
||||
return result
|
||||
elseif string.match(result, "not found") then
|
||||
error "Compilation only available with full Metalua"
|
||||
else error (result) end
|
||||
end
|
||||
end
|
||||
|
||||
function CONV :ast_to_proto(ast, name)
|
||||
checks('metalua.compiler', 'table', '?string')
|
||||
return get_bytecode_compiler().ast_to_proto(ast, name), name
|
||||
end
|
||||
|
||||
function CONV :proto_to_bytecode(proto, name)
|
||||
return get_bytecode_compiler().proto_to_bytecode(proto), name
|
||||
end
|
||||
|
||||
function CONV :bytecode_to_function(bc, name)
|
||||
checks('metalua.compiler', 'string', '?string')
|
||||
return loadstring(bc, name)
|
||||
end
|
||||
|
||||
-- Create all sensible combinations
|
||||
for i=1,#M.sequence do
|
||||
local src = M.sequence[i]
|
||||
for j=i+2, #M.sequence do
|
||||
local dst = M.sequence[j]
|
||||
local dst_name = src.."_to_"..dst
|
||||
local my_arg_types = arg_types[src]
|
||||
local functions = { }
|
||||
for k=i, j-1 do
|
||||
local name = M.sequence[k].."_to_"..M.sequence[k+1]
|
||||
local f = assert(CONV[name], name)
|
||||
table.insert (functions, f)
|
||||
end
|
||||
CONV[dst_name] = function(self, a, b)
|
||||
checks('metalua.compiler', unpack(my_arg_types))
|
||||
for _, f in ipairs(functions) do
|
||||
a, b = f(self, a, b)
|
||||
end
|
||||
return a, b
|
||||
end
|
||||
--printf("Created M.%s out of %s", dst_name, table.concat(n, ', '))
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- This one goes in the "wrong" direction, cannot be composed.
|
||||
--------------------------------------------------------------------------------
|
||||
function CONV :function_to_bytecode(...) return string.dump(...) end
|
||||
|
||||
function CONV :ast_to_src(...)
|
||||
require 'metalua.loader' -- ast_to_string isn't written in plain lua
|
||||
return require 'metalua.compiler.ast_to_src' (...)
|
||||
end
|
||||
|
||||
local MT = { __index=CONV, __type='metalua.compiler' }
|
||||
|
||||
function M.new()
|
||||
local parser = require 'metalua.compiler.parser' .new()
|
||||
local self = { parser = parser }
|
||||
setmetatable(self, MT)
|
||||
return self
|
||||
end
|
||||
|
||||
return M
|
||||
42
lualibs/metalua/compiler/parser.lua
Normal file
42
lualibs/metalua/compiler/parser.lua
Normal file
@@ -0,0 +1,42 @@
|
||||
--------------------------------------------------------------------------------
|
||||
-- Copyright (c) 2006-2013 Fabien Fleutot and others.
|
||||
--
|
||||
-- All rights reserved.
|
||||
--
|
||||
-- This program and the accompanying materials are made available
|
||||
-- under the terms of the Eclipse Public License v1.0 which
|
||||
-- accompanies this distribution, and is available at
|
||||
-- http://www.eclipse.org/legal/epl-v10.html
|
||||
--
|
||||
-- This program and the accompanying materials are also made available
|
||||
-- under the terms of the MIT public license which accompanies this
|
||||
-- distribution, and is available at http://www.lua.org/license.html
|
||||
--
|
||||
-- Contributors:
|
||||
-- Fabien Fleutot - API and implementation
|
||||
--
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
-- Export all public APIs from sub-modules, squashed into a flat spacename
|
||||
|
||||
local MT = { __type='metalua.compiler.parser' }
|
||||
|
||||
local MODULE_REL_NAMES = { "annot.grammar", "expr", "meta", "misc",
|
||||
"stat", "table", "ext" }
|
||||
|
||||
local function new()
|
||||
local M = {
|
||||
lexer = require "metalua.compiler.parser.lexer" ();
|
||||
extensions = { } }
|
||||
for _, rel_name in ipairs(MODULE_REL_NAMES) do
|
||||
local abs_name = "metalua.compiler.parser."..rel_name
|
||||
local extender = require (abs_name)
|
||||
if not M.extensions[abs_name] then
|
||||
if type (extender) == 'function' then extender(M) end
|
||||
M.extensions[abs_name] = extender
|
||||
end
|
||||
end
|
||||
return setmetatable(M, MT)
|
||||
end
|
||||
|
||||
return { new = new }
|
||||
48
lualibs/metalua/compiler/parser/annot/generator.lua
Normal file
48
lualibs/metalua/compiler/parser/annot/generator.lua
Normal file
@@ -0,0 +1,48 @@
|
||||
--------------------------------------------------------------------------------
|
||||
-- Copyright (c) 2006-2013 Fabien Fleutot and others.
|
||||
--
|
||||
-- All rights reserved.
|
||||
--
|
||||
-- This program and the accompanying materials are made available
|
||||
-- under the terms of the Eclipse Public License v1.0 which
|
||||
-- accompanies this distribution, and is available at
|
||||
-- http://www.eclipse.org/legal/epl-v10.html
|
||||
--
|
||||
-- This program and the accompanying materials are also made available
|
||||
-- under the terms of the MIT public license which accompanies this
|
||||
-- distribution, and is available at http://www.lua.org/license.html
|
||||
--
|
||||
-- Contributors:
|
||||
-- Fabien Fleutot - API and implementation
|
||||
--
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
require 'checks'
|
||||
local gg = require 'metalua.grammar.generator'
|
||||
local M = { }
|
||||
|
||||
function M.opt(mlc, primary, a_type)
|
||||
checks('table', 'table|function', 'string')
|
||||
return gg.sequence{
|
||||
primary,
|
||||
gg.onkeyword{ "#", function() return assert(mlc.annot[a_type]) end },
|
||||
builder = function(x)
|
||||
local t, annot = unpack(x)
|
||||
return annot and { tag='Annot', t, annot } or t
|
||||
end }
|
||||
end
|
||||
|
||||
-- split a list of "foo" and "`Annot{foo, annot}" into a list of "foo"
|
||||
-- and a list of "annot".
|
||||
-- No annot list is returned if none of the elements were annotated.
|
||||
function M.split(lst)
|
||||
local x, a, some = { }, { }, false
|
||||
for i, p in ipairs(lst) do
|
||||
if p.tag=='Annot' then
|
||||
some, x[i], a[i] = true, unpack(p)
|
||||
else x[i] = p end
|
||||
end
|
||||
if some then return x, a else return lst end
|
||||
end
|
||||
|
||||
return M
|
||||
112
lualibs/metalua/compiler/parser/annot/grammar.lua
Normal file
112
lualibs/metalua/compiler/parser/annot/grammar.lua
Normal file
@@ -0,0 +1,112 @@
|
||||
--------------------------------------------------------------------------------
|
||||
-- Copyright (c) 2006-2013 Fabien Fleutot and others.
|
||||
--
|
||||
-- All rights reserved.
|
||||
--
|
||||
-- This program and the accompanying materials are made available
|
||||
-- under the terms of the Eclipse Public License v1.0 which
|
||||
-- accompanies this distribution, and is available at
|
||||
-- http://www.eclipse.org/legal/epl-v10.html
|
||||
--
|
||||
-- This program and the accompanying materials are also made available
|
||||
-- under the terms of the MIT public license which accompanies this
|
||||
-- distribution, and is available at http://www.lua.org/license.html
|
||||
--
|
||||
-- Contributors:
|
||||
-- Fabien Fleutot - API and implementation
|
||||
--
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
local gg = require 'metalua.grammar.generator'
|
||||
|
||||
return function(M)
|
||||
local _M = gg.future(M)
|
||||
M.lexer :add '->'
|
||||
local A = { }
|
||||
local _A = gg.future(A)
|
||||
M.annot = A
|
||||
|
||||
-- Type identifier: Lua keywords such as `"nil"` allowed.
|
||||
function M.annot.tid(lx)
|
||||
local w = lx :next()
|
||||
local t = w.tag
|
||||
if t=='Keyword' and w[1] :match '^[%a_][%w_]*$' or w.tag=='Id'
|
||||
then return {tag='TId'; lineinfo=w.lineinfo; w[1]}
|
||||
else return gg.parse_error (lx, 'tid expected') end
|
||||
end
|
||||
|
||||
local field_types = { var='TVar'; const='TConst';
|
||||
currently='TCurrently'; field='TField' }
|
||||
|
||||
-- TODO check lineinfo
|
||||
function M.annot.tf(lx)
|
||||
local tk = lx:next()
|
||||
local w = tk[1]
|
||||
local tag = field_types[w]
|
||||
if not tag then error ('Invalid field type '..w)
|
||||
elseif tag=='TField' then return {tag='TField'} else
|
||||
local te = M.te(lx)
|
||||
return {tag=tag; te}
|
||||
end
|
||||
end
|
||||
|
||||
M.annot.tebar_content = gg.list{
|
||||
name = 'tebar content',
|
||||
primary = _A.te,
|
||||
separators = { ",", ";" },
|
||||
terminators = ")" }
|
||||
|
||||
M.annot.tebar = gg.multisequence{
|
||||
name = 'annot.tebar',
|
||||
--{ '*', builder = 'TDynbar' }, -- maybe not user-available
|
||||
{ '(', _A.tebar_content, ')',
|
||||
builder = function(x) return x[1] end },
|
||||
{ _A.te }
|
||||
}
|
||||
|
||||
M.annot.te = gg.multisequence{
|
||||
name = 'annot.te',
|
||||
{ _A.tid, builder=function(x) return x[1] end },
|
||||
{ '*', builder = 'TDyn' },
|
||||
{ "[",
|
||||
gg.list{
|
||||
primary = gg.sequence{
|
||||
_M.expr, "=", _A.tf,
|
||||
builder = 'TPair'
|
||||
},
|
||||
separators = { ",", ";" },
|
||||
terminators = { "]", "|" } },
|
||||
gg.onkeyword{ "|", _A.tf },
|
||||
"]",
|
||||
builder = function(x)
|
||||
local fields, other = unpack(x)
|
||||
return { tag='TTable', other or {tag='TField'}, fields }
|
||||
end }, -- "[ ... ]"
|
||||
{ '(', _A.tebar_content, ')', '->', '(', _A.tebar_content, ')',
|
||||
builder = function(x)
|
||||
local p, r = unpack(x)
|
||||
return {tag='TFunction', p, r }
|
||||
end } }
|
||||
|
||||
M.annot.ts = gg.multisequence{
|
||||
name = 'annot.ts',
|
||||
{ 'return', _A.tebar_content, builder='TReturn' },
|
||||
{ _A.tid, builder = function(x)
|
||||
if x[1][1]=='pass' then return {tag='TPass'}
|
||||
else error "Bad statement type" end
|
||||
end } }
|
||||
|
||||
-- TODO: add parsers for statements:
|
||||
-- #return tebar
|
||||
-- #alias = te
|
||||
-- #ell = tf
|
||||
--[[
|
||||
M.annot.stat_annot = gg.sequence{
|
||||
gg.list{ primary=_A.tid, separators='.' },
|
||||
'=',
|
||||
XXX??,
|
||||
builder = 'Annot' }
|
||||
--]]
|
||||
|
||||
return M.annot
|
||||
end
|
||||
27
lualibs/metalua/compiler/parser/common.lua
Normal file
27
lualibs/metalua/compiler/parser/common.lua
Normal file
@@ -0,0 +1,27 @@
|
||||
--------------------------------------------------------------------------------
|
||||
-- Copyright (c) 2006-2013 Fabien Fleutot and others.
|
||||
--
|
||||
-- All rights reserved.
|
||||
--
|
||||
-- This program and the accompanying materials are made available
|
||||
-- under the terms of the Eclipse Public License v1.0 which
|
||||
-- accompanies this distribution, and is available at
|
||||
-- http://www.eclipse.org/legal/epl-v10.html
|
||||
--
|
||||
-- This program and the accompanying materials are also made available
|
||||
-- under the terms of the MIT public license which accompanies this
|
||||
-- distribution, and is available at http://www.lua.org/license.html
|
||||
--
|
||||
-- Contributors:
|
||||
-- Fabien Fleutot - API and implementation
|
||||
--
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
-- Shared common parser table. It will be filled by parser.init(),
|
||||
-- and every other module will be able to call its elements at runtime.
|
||||
--
|
||||
-- If the table was directly created in parser.init, a circular
|
||||
-- dependency would be created: parser.init depends on other modules to fill the table,
|
||||
-- so other modules can't simultaneously depend on it.
|
||||
|
||||
return { }
|
||||
206
lualibs/metalua/compiler/parser/expr.lua
Normal file
206
lualibs/metalua/compiler/parser/expr.lua
Normal file
@@ -0,0 +1,206 @@
|
||||
-------------------------------------------------------------------------------
|
||||
-- Copyright (c) 2006-2013 Fabien Fleutot and others.
|
||||
--
|
||||
-- All rights reserved.
|
||||
--
|
||||
-- This program and the accompanying materials are made available
|
||||
-- under the terms of the Eclipse Public License v1.0 which
|
||||
-- accompanies this distribution, and is available at
|
||||
-- http://www.eclipse.org/legal/epl-v10.html
|
||||
--
|
||||
-- This program and the accompanying materials are also made available
|
||||
-- under the terms of the MIT public license which accompanies this
|
||||
-- distribution, and is available at http://www.lua.org/license.html
|
||||
--
|
||||
-- Contributors:
|
||||
-- Fabien Fleutot - API and implementation
|
||||
--
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
--
|
||||
-- Exported API:
|
||||
-- * [mlp.expr()]
|
||||
-- * [mlp.expr_list()]
|
||||
-- * [mlp.func_val()]
|
||||
--
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
local pp = require 'metalua.pprint'
|
||||
local gg = require 'metalua.grammar.generator'
|
||||
local annot = require 'metalua.compiler.parser.annot.generator'
|
||||
|
||||
return function(M)
|
||||
local _M = gg.future(M)
|
||||
local _table = gg.future(M, 'table')
|
||||
local _meta = gg.future(M, 'meta') -- TODO move to ext?
|
||||
local _annot = gg.future(M, 'annot') -- TODO move to annot
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Non-empty expression list. Actually, this isn't used here, but that's
|
||||
-- handy to give to users.
|
||||
--------------------------------------------------------------------------------
|
||||
M.expr_list = gg.list{ primary=_M.expr, separators="," }
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Helpers for function applications / method applications
|
||||
--------------------------------------------------------------------------------
|
||||
M.func_args_content = gg.list{
|
||||
name = "function arguments",
|
||||
primary = _M.expr,
|
||||
separators = ",",
|
||||
terminators = ")" }
|
||||
|
||||
-- Used to parse methods
|
||||
M.method_args = gg.multisequence{
|
||||
name = "function argument(s)",
|
||||
{ "{", _table.content, "}" },
|
||||
{ "(", _M.func_args_content, ")", builder = unpack },
|
||||
{ "+{", _meta.quote_content, "}" },
|
||||
-- TODO lineinfo?
|
||||
function(lx) local r = M.opt_string(lx); return r and {r} or { } end }
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- [func_val] parses a function, from opening parameters parenthese to
|
||||
-- "end" keyword included. Used for anonymous functions as well as
|
||||
-- function declaration statements (both local and global).
|
||||
--
|
||||
-- It's wrapped in a [_func_val] eta expansion, so that when expr
|
||||
-- parser uses the latter, they will notice updates of [func_val]
|
||||
-- definitions.
|
||||
--------------------------------------------------------------------------------
|
||||
M.func_params_content = gg.list{
|
||||
name="function parameters",
|
||||
gg.multisequence{ { "...", builder = "Dots" }, annot.opt(M, _M.id, 'te') },
|
||||
separators = ",", terminators = {")", "|"} }
|
||||
|
||||
-- TODO move to annot
|
||||
M.func_val = gg.sequence{
|
||||
name = "function body",
|
||||
"(", _M.func_params_content, ")", _M.block, "end",
|
||||
builder = function(x)
|
||||
local params, body = unpack(x)
|
||||
local annots, some = { }, false
|
||||
for i, p in ipairs(params) do
|
||||
if p.tag=='Annot' then
|
||||
params[i], annots[i], some = p[1], p[2], true
|
||||
else annots[i] = false end
|
||||
end
|
||||
if some then return { tag='Function', params, body, annots }
|
||||
else return { tag='Function', params, body } end
|
||||
end }
|
||||
|
||||
local func_val = function(lx) return M.func_val(lx) end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Default parser for primary expressions
|
||||
--------------------------------------------------------------------------------
|
||||
function M.id_or_literal (lx)
|
||||
local a = lx:next()
|
||||
if a.tag~="Id" and a.tag~="String" and a.tag~="Number" then
|
||||
local msg
|
||||
if a.tag=='Eof' then
|
||||
msg = "End of file reached when an expression was expected"
|
||||
elseif a.tag=='Keyword' then
|
||||
msg = "An expression was expected, and `"..a[1]..
|
||||
"' can't start an expression"
|
||||
else
|
||||
msg = "Unexpected expr token " .. pp.tostring (a)
|
||||
end
|
||||
gg.parse_error (lx, msg)
|
||||
end
|
||||
return a
|
||||
end
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Builder generator for operators. Wouldn't be worth it if "|x|" notation
|
||||
-- were allowed, but then lua 5.1 wouldn't compile it
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
-- opf1 = |op| |_,a| `Op{ op, a }
|
||||
local function opf1 (op) return
|
||||
function (_,a) return { tag="Op", op, a } end end
|
||||
|
||||
-- opf2 = |op| |a,_,b| `Op{ op, a, b }
|
||||
local function opf2 (op) return
|
||||
function (a,_,b) return { tag="Op", op, a, b } end end
|
||||
|
||||
-- opf2r = |op| |a,_,b| `Op{ op, b, a } -- (args reversed)
|
||||
local function opf2r (op) return
|
||||
function (a,_,b) return { tag="Op", op, b, a } end end
|
||||
|
||||
local function op_ne(a, _, b)
|
||||
-- This version allows to remove the "ne" operator from the AST definition.
|
||||
-- However, it doesn't always produce the exact same bytecode as Lua 5.1.
|
||||
return { tag="Op", "not",
|
||||
{ tag="Op", "eq", a, b, lineinfo= {
|
||||
first = a.lineinfo.first, last = b.lineinfo.last } } }
|
||||
end
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
--
|
||||
-- complete expression
|
||||
--
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
-- FIXME: set line number. In [expr] transformers probably
|
||||
M.expr = gg.expr {
|
||||
name = "expression",
|
||||
primary = gg.multisequence{
|
||||
name = "expr primary",
|
||||
{ "(", _M.expr, ")", builder = "Paren" },
|
||||
{ "function", _M.func_val, builder = unpack },
|
||||
{ "-{", _meta.splice_content, "}", builder = unpack },
|
||||
{ "+{", _meta.quote_content, "}", builder = unpack },
|
||||
{ "nil", builder = "Nil" },
|
||||
{ "true", builder = "True" },
|
||||
{ "false", builder = "False" },
|
||||
{ "...", builder = "Dots" },
|
||||
{ "{", _table.content, "}", builder = unpack },
|
||||
_M.id_or_literal },
|
||||
|
||||
infix = {
|
||||
name = "expr infix op",
|
||||
{ "+", prec = 60, builder = opf2 "add" },
|
||||
{ "-", prec = 60, builder = opf2 "sub" },
|
||||
{ "*", prec = 70, builder = opf2 "mul" },
|
||||
{ "/", prec = 70, builder = opf2 "div" },
|
||||
{ "%", prec = 70, builder = opf2 "mod" },
|
||||
{ "^", prec = 90, builder = opf2 "pow", assoc = "right" },
|
||||
{ "..", prec = 40, builder = opf2 "concat", assoc = "right" },
|
||||
{ "==", prec = 30, builder = opf2 "eq" },
|
||||
{ "~=", prec = 30, builder = op_ne },
|
||||
{ "<", prec = 30, builder = opf2 "lt" },
|
||||
{ "<=", prec = 30, builder = opf2 "le" },
|
||||
{ ">", prec = 30, builder = opf2r "lt" },
|
||||
{ ">=", prec = 30, builder = opf2r "le" },
|
||||
{ "and",prec = 20, builder = opf2 "and" },
|
||||
{ "or", prec = 10, builder = opf2 "or" } },
|
||||
|
||||
prefix = {
|
||||
name = "expr prefix op",
|
||||
{ "not", prec = 80, builder = opf1 "not" },
|
||||
{ "#", prec = 80, builder = opf1 "len" },
|
||||
{ "-", prec = 80, builder = opf1 "unm" } },
|
||||
|
||||
suffix = {
|
||||
name = "expr suffix op",
|
||||
{ "[", _M.expr, "]", builder = function (tab, idx)
|
||||
return {tag="Index", tab, idx[1]} end},
|
||||
{ ".", _M.id, builder = function (tab, field)
|
||||
return {tag="Index", tab, _M.id2string(field[1])} end },
|
||||
{ "(", _M.func_args_content, ")", builder = function(f, args)
|
||||
return {tag="Call", f, unpack(args[1])} end },
|
||||
{ "{", _table.content, "}", builder = function (f, arg)
|
||||
return {tag="Call", f, arg[1]} end},
|
||||
{ ":", _M.id, _M.method_args, builder = function (obj, post)
|
||||
local m_name, args = unpack(post)
|
||||
return {tag="Invoke", obj, _M.id2string(m_name), unpack(args)} end},
|
||||
{ "+{", _meta.quote_content, "}", builder = function (f, arg)
|
||||
return {tag="Call", f, arg[1] } end },
|
||||
default = { name="opt_string_arg", parse = _M.opt_string, builder = function(f, arg)
|
||||
return {tag="Call", f, arg } end } } }
|
||||
return M
|
||||
end
|
||||
96
lualibs/metalua/compiler/parser/ext.lua
Normal file
96
lualibs/metalua/compiler/parser/ext.lua
Normal file
@@ -0,0 +1,96 @@
|
||||
-------------------------------------------------------------------------------
|
||||
-- Copyright (c) 2006-2013 Fabien Fleutot and others.
|
||||
--
|
||||
-- All rights reserved.
|
||||
--
|
||||
-- This program and the accompanying materials are made available
|
||||
-- under the terms of the Eclipse Public License v1.0 which
|
||||
-- accompanies this distribution, and is available at
|
||||
-- http://www.eclipse.org/legal/epl-v10.html
|
||||
--
|
||||
-- This program and the accompanying materials are also made available
|
||||
-- under the terms of the MIT public license which accompanies this
|
||||
-- distribution, and is available at http://www.lua.org/license.html
|
||||
--
|
||||
-- Contributors:
|
||||
-- Fabien Fleutot - API and implementation
|
||||
--
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
--
|
||||
-- Non-Lua syntax extensions
|
||||
--
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
local gg = require 'metalua.grammar.generator'
|
||||
|
||||
return function(M)
|
||||
|
||||
local _M = gg.future(M)
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
-- Algebraic Datatypes
|
||||
----------------------------------------------------------------------------
|
||||
local function adt (lx)
|
||||
local node = _M.id (lx)
|
||||
local tagval = node[1]
|
||||
-- tagkey = `Pair{ `String "key", `String{ -{tagval} } }
|
||||
local tagkey = { tag="Pair", {tag="String", "tag"}, {tag="String", tagval} }
|
||||
if lx:peek().tag == "String" or lx:peek().tag == "Number" then
|
||||
-- TODO support boolean litterals
|
||||
return { tag="Table", tagkey, lx:next() }
|
||||
elseif lx:is_keyword (lx:peek(), "{") then
|
||||
local x = M.table.table (lx)
|
||||
table.insert (x, 1, tagkey)
|
||||
return x
|
||||
else return { tag="Table", tagkey } end
|
||||
end
|
||||
|
||||
M.adt = gg.sequence{ "`", adt, builder = unpack }
|
||||
|
||||
M.expr.primary :add(M.adt)
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
-- Anonymous lambda
|
||||
----------------------------------------------------------------------------
|
||||
M.lambda_expr = gg.sequence{
|
||||
"|", _M.func_params_content, "|", _M.expr,
|
||||
builder = function (x)
|
||||
local li = x[2].lineinfo
|
||||
return { tag="Function", x[1],
|
||||
{ {tag="Return", x[2], lineinfo=li }, lineinfo=li } }
|
||||
end }
|
||||
|
||||
M.expr.primary :add (M.lambda_expr)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Allows to write "a `f` b" instead of "f(a, b)". Taken from Haskell.
|
||||
--------------------------------------------------------------------------------
|
||||
function M.expr_in_backquotes (lx) return M.expr(lx, 35) end -- 35=limited precedence
|
||||
M.expr.infix :add{ name = "infix function",
|
||||
"`", _M.expr_in_backquotes, "`", prec = 35, assoc="left",
|
||||
builder = function(a, op, b) return {tag="Call", op[1], a, b} end }
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- C-style op+assignments
|
||||
-- TODO: no protection against side-effects in LHS vars.
|
||||
--------------------------------------------------------------------------------
|
||||
local function op_assign(kw, op)
|
||||
local function rhs(a, b) return { tag="Op", op, a, b } end
|
||||
local function f(a,b)
|
||||
if #a ~= #b then gg.parse_error "assymetric operator+assignment" end
|
||||
local right = { }
|
||||
local r = { tag="Set", a, right }
|
||||
for i=1, #a do right[i] = { tag="Op", op, a[i], b[i] } end
|
||||
return r
|
||||
end
|
||||
M.lexer :add (kw)
|
||||
M.assignments[kw] = f
|
||||
end
|
||||
|
||||
local ops = { add='+='; sub='-='; mul='*='; div='/=' }
|
||||
for ast_op_name, keyword in pairs(ops) do op_assign(keyword, ast_op_name) end
|
||||
|
||||
return M
|
||||
end
|
||||
43
lualibs/metalua/compiler/parser/lexer.lua
Normal file
43
lualibs/metalua/compiler/parser/lexer.lua
Normal file
@@ -0,0 +1,43 @@
|
||||
--------------------------------------------------------------------------------
|
||||
-- Copyright (c) 2006-2014 Fabien Fleutot and others.
|
||||
--
|
||||
-- All rights reserved.
|
||||
--
|
||||
-- This program and the accompanying materials are made available
|
||||
-- under the terms of the Eclipse Public License v1.0 which
|
||||
-- accompanies this distribution, and is available at
|
||||
-- http://www.eclipse.org/legal/epl-v10.html
|
||||
--
|
||||
-- This program and the accompanying materials are also made available
|
||||
-- under the terms of the MIT public license which accompanies this
|
||||
-- distribution, and is available at http://www.lua.org/license.html
|
||||
--
|
||||
-- Contributors:
|
||||
-- Fabien Fleutot - API and implementation
|
||||
--
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- Generate a new lua-specific lexer, derived from the generic lexer.
|
||||
----------------------------------------------------------------------
|
||||
|
||||
local generic_lexer = require 'metalua.grammar.lexer'
|
||||
|
||||
return function()
|
||||
local lexer = generic_lexer.lexer :clone()
|
||||
|
||||
local keywords = {
|
||||
"and", "break", "do", "else", "elseif",
|
||||
"end", "false", "for", "function",
|
||||
"goto", -- Lua5.2
|
||||
"if",
|
||||
"in", "local", "nil", "not", "or", "repeat",
|
||||
"return", "then", "true", "until", "while",
|
||||
"...", "..", "==", ">=", "<=", "~=",
|
||||
"::", -- Lua5,2
|
||||
"+{", "-{" } -- Metalua
|
||||
|
||||
for _, w in ipairs(keywords) do lexer :add (w) end
|
||||
|
||||
return lexer
|
||||
end
|
||||
138
lualibs/metalua/compiler/parser/meta.lua
Normal file
138
lualibs/metalua/compiler/parser/meta.lua
Normal file
@@ -0,0 +1,138 @@
|
||||
-------------------------------------------------------------------------------
|
||||
-- Copyright (c) 2006-2014 Fabien Fleutot and others.
|
||||
--
|
||||
-- All rights reserved.
|
||||
--
|
||||
-- This program and the accompanying materials are made available
|
||||
-- under the terms of the Eclipse Public License v1.0 which
|
||||
-- accompanies this distribution, and is available at
|
||||
-- http://www.eclipse.org/legal/epl-v10.html
|
||||
--
|
||||
-- This program and the accompanying materials are also made available
|
||||
-- under the terms of the MIT public license which accompanies this
|
||||
-- distribution, and is available at http://www.lua.org/license.html
|
||||
--
|
||||
-- Contributors:
|
||||
-- Fabien Fleutot - API and implementation
|
||||
--
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
-- Compile-time metaprogramming features: splicing ASTs generated during compilation,
|
||||
-- AST quasi-quoting helpers.
|
||||
|
||||
local gg = require 'metalua.grammar.generator'
|
||||
|
||||
return function(M)
|
||||
local _M = gg.future(M)
|
||||
M.meta={ }
|
||||
local _MM = gg.future(M.meta)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- External splicing: compile an AST into a chunk, load and evaluate
|
||||
-- that chunk, and replace the chunk by its result (which must also be
|
||||
-- an AST).
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
-- TODO: that's not part of the parser
|
||||
function M.meta.eval (ast)
|
||||
-- TODO: should there be one mlc per splice, or per parser instance?
|
||||
local mlc = require 'metalua.compiler'.new()
|
||||
local f = mlc :ast_to_function (ast, '=splice')
|
||||
local result=f(M) -- splices act on the current parser
|
||||
return result
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
-- Going from an AST to an AST representing that AST
|
||||
-- the only hash-part key being lifted is `"tag"`.
|
||||
-- Doesn't lift subtrees protected inside a `Splice{ ... }.
|
||||
-- e.g. change `Foo{ 123 } into
|
||||
-- `Table{ `Pair{ `String "tag", `String "foo" }, `Number 123 }
|
||||
----------------------------------------------------------------------------
|
||||
local function lift (t)
|
||||
--print("QUOTING:", table.tostring(t, 60,'nohash'))
|
||||
local cases = { }
|
||||
function cases.table (t)
|
||||
local mt = { tag = "Table" }
|
||||
--table.insert (mt, { tag = "Pair", quote "quote", { tag = "True" } })
|
||||
if t.tag == "Splice" then
|
||||
assert (#t==1, "Invalid splice")
|
||||
local sp = t[1]
|
||||
return sp
|
||||
elseif t.tag then
|
||||
table.insert (mt, { tag="Pair", lift "tag", lift(t.tag) })
|
||||
end
|
||||
for _, v in ipairs (t) do
|
||||
table.insert (mt, lift(v))
|
||||
end
|
||||
return mt
|
||||
end
|
||||
function cases.number (t) return { tag = "Number", t, quote = true } end
|
||||
function cases.string (t) return { tag = "String", t, quote = true } end
|
||||
function cases.boolean (t) return { tag = t and "True" or "False", t, quote = true } end
|
||||
local f = cases [type(t)]
|
||||
if f then return f(t) else error ("Cannot quote an AST containing "..tostring(t)) end
|
||||
end
|
||||
M.meta.lift = lift
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- when this variable is false, code inside [-{...}] is compiled and
|
||||
-- avaluated immediately. When it's true (supposedly when we're
|
||||
-- parsing data inside a quasiquote), [-{foo}] is replaced by
|
||||
-- [`Splice{foo}], which will be unpacked by [quote()].
|
||||
--------------------------------------------------------------------------------
|
||||
local in_a_quote = false
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Parse the inside of a "-{ ... }"
|
||||
--------------------------------------------------------------------------------
|
||||
function M.meta.splice_content (lx)
|
||||
local parser_name = "expr"
|
||||
if lx:is_keyword (lx:peek(2), ":") then
|
||||
local a = lx:next()
|
||||
lx:next() -- skip ":"
|
||||
assert (a.tag=="Id", "Invalid splice parser name")
|
||||
parser_name = a[1]
|
||||
end
|
||||
-- TODO FIXME running a new parser with the old lexer?!
|
||||
local parser = require 'metalua.compiler.parser'.new()
|
||||
local ast = parser [parser_name](lx)
|
||||
if in_a_quote then -- only prevent quotation in this subtree
|
||||
--printf("SPLICE_IN_QUOTE:\n%s", _G.table.tostring(ast, "nohash", 60))
|
||||
return { tag="Splice", ast }
|
||||
else -- convert in a block, eval, replace with result
|
||||
if parser_name == "expr" then ast = { { tag="Return", ast } }
|
||||
elseif parser_name == "stat" then ast = { ast }
|
||||
elseif parser_name ~= "block" then
|
||||
error ("splice content must be an expr, stat or block") end
|
||||
--printf("EXEC THIS SPLICE:\n%s", _G.table.tostring(ast, "nohash", 60))
|
||||
return M.meta.eval (ast)
|
||||
end
|
||||
end
|
||||
|
||||
M.meta.splice = gg.sequence{ "-{", _MM.splice_content, "}", builder=unpack }
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Parse the inside of a "+{ ... }"
|
||||
--------------------------------------------------------------------------------
|
||||
function M.meta.quote_content (lx)
|
||||
local parser
|
||||
if lx:is_keyword (lx:peek(2), ":") then -- +{parser: content }
|
||||
local parser_name = M.id(lx)[1]
|
||||
parser = M[parser_name]
|
||||
lx:next() -- skip ":"
|
||||
else -- +{ content }
|
||||
parser = M.expr
|
||||
end
|
||||
|
||||
local prev_iq = in_a_quote
|
||||
in_a_quote = true
|
||||
--print("IN_A_QUOTE")
|
||||
local content = parser (lx)
|
||||
local q_content = M.meta.lift (content)
|
||||
in_a_quote = prev_iq
|
||||
return q_content
|
||||
end
|
||||
|
||||
return M
|
||||
end
|
||||
147
lualibs/metalua/compiler/parser/misc.lua
Normal file
147
lualibs/metalua/compiler/parser/misc.lua
Normal file
@@ -0,0 +1,147 @@
|
||||
-------------------------------------------------------------------------------
|
||||
-- Copyright (c) 2006-2013 Fabien Fleutot and others.
|
||||
--
|
||||
-- All rights reserved.
|
||||
--
|
||||
-- This program and the accompanying materials are made available
|
||||
-- under the terms of the Eclipse Public License v1.0 which
|
||||
-- accompanies this distribution, and is available at
|
||||
-- http://www.eclipse.org/legal/epl-v10.html
|
||||
--
|
||||
-- This program and the accompanying materials are also made available
|
||||
-- under the terms of the MIT public license which accompanies this
|
||||
-- distribution, and is available at http://www.lua.org/license.html
|
||||
--
|
||||
-- Contributors:
|
||||
-- Fabien Fleutot - API and implementation
|
||||
--
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
--
|
||||
-- Summary: metalua parser, miscellaneous utility functions.
|
||||
--
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
--
|
||||
-- Exported API:
|
||||
-- * [mlp.fget()]
|
||||
-- * [mlp.id()]
|
||||
-- * [mlp.opt_id()]
|
||||
-- * [mlp.id_list()]
|
||||
-- * [mlp.string()]
|
||||
-- * [mlp.opt_string()]
|
||||
-- * [mlp.id2string()]
|
||||
--
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
local gg = require 'metalua.grammar.generator'
|
||||
|
||||
-- TODO: replace splice-aware versions with naive ones, move etensions in ./meta
|
||||
|
||||
return function(M)
|
||||
local _M = gg.future(M)
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Try to read an identifier (possibly as a splice), or return [false] if no
|
||||
-- id is found.
|
||||
--------------------------------------------------------------------------------
|
||||
function M.opt_id (lx)
|
||||
local a = lx:peek();
|
||||
if lx:is_keyword (a, "-{") then
|
||||
local v = M.meta.splice(lx)
|
||||
if v.tag ~= "Id" and v.tag ~= "Splice" then
|
||||
gg.parse_error(lx, "Bad id splice")
|
||||
end
|
||||
return v
|
||||
elseif a.tag == "Id" then return lx:next()
|
||||
else return false end
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Mandatory reading of an id: causes an error if it can't read one.
|
||||
--------------------------------------------------------------------------------
|
||||
function M.id (lx)
|
||||
return M.opt_id (lx) or gg.parse_error(lx,"Identifier expected")
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Common helper function
|
||||
--------------------------------------------------------------------------------
|
||||
M.id_list = gg.list { primary = _M.id, separators = "," }
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Converts an identifier into a string. Hopefully one day it'll handle
|
||||
-- splices gracefully, but that proves quite tricky.
|
||||
--------------------------------------------------------------------------------
|
||||
function M.id2string (id)
|
||||
--print("id2string:", disp.ast(id))
|
||||
if id.tag == "Id" then id.tag = "String"; return id
|
||||
elseif id.tag == "Splice" then
|
||||
error ("id2string on splice not implemented")
|
||||
-- Evaluating id[1] will produce `Id{ xxx },
|
||||
-- and we want it to produce `String{ xxx }.
|
||||
-- The following is the plain notation of:
|
||||
-- +{ `String{ `Index{ `Splice{ -{id[1]} }, `Number 1 } } }
|
||||
return { tag="String", { tag="Index", { tag="Splice", id[1] },
|
||||
{ tag="Number", 1 } } }
|
||||
else error ("Identifier expected: "..table.tostring(id, 'nohash')) end
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Read a string, possibly spliced, or return an error if it can't
|
||||
--------------------------------------------------------------------------------
|
||||
function M.string (lx)
|
||||
local a = lx:peek()
|
||||
if lx:is_keyword (a, "-{") then
|
||||
local v = M.meta.splice(lx)
|
||||
if v.tag ~= "String" and v.tag ~= "Splice" then
|
||||
gg.parse_error(lx,"Bad string splice")
|
||||
end
|
||||
return v
|
||||
elseif a.tag == "String" then return lx:next()
|
||||
else error "String expected" end
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Try to read a string, or return false if it can't. No splice allowed.
|
||||
--------------------------------------------------------------------------------
|
||||
function M.opt_string (lx)
|
||||
return lx:peek().tag == "String" and lx:next()
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Chunk reader: block + Eof
|
||||
--------------------------------------------------------------------------------
|
||||
function M.skip_initial_sharp_comment (lx)
|
||||
-- Dirty hack: I'm happily fondling lexer's private parts
|
||||
-- FIXME: redundant with lexer:newstream()
|
||||
lx :sync()
|
||||
local i = lx.src:match ("^#.-\n()", lx.i)
|
||||
if i then
|
||||
lx.i = i
|
||||
lx.column_offset = i
|
||||
lx.line = lx.line and lx.line + 1 or 1
|
||||
end
|
||||
end
|
||||
|
||||
local function chunk (lx)
|
||||
if lx:peek().tag == 'Eof' then
|
||||
return { } -- handle empty files
|
||||
else
|
||||
M.skip_initial_sharp_comment (lx)
|
||||
local chunk = M.block (lx)
|
||||
if lx:peek().tag ~= "Eof" then
|
||||
gg.parse_error(lx, "End-of-file expected")
|
||||
end
|
||||
return chunk
|
||||
end
|
||||
end
|
||||
|
||||
-- chunk is wrapped in a sequence so that it has a "transformer" field.
|
||||
M.chunk = gg.sequence { chunk, builder = unpack }
|
||||
|
||||
return M
|
||||
end
|
||||
279
lualibs/metalua/compiler/parser/stat.lua
Normal file
279
lualibs/metalua/compiler/parser/stat.lua
Normal file
@@ -0,0 +1,279 @@
|
||||
------------------------------------------------------------------------------
|
||||
-- Copyright (c) 2006-2013 Fabien Fleutot and others.
|
||||
--
|
||||
-- All rights reserved.
|
||||
--
|
||||
-- This program and the accompanying materials are made available
|
||||
-- under the terms of the Eclipse Public License v1.0 which
|
||||
-- accompanies this distribution, and is available at
|
||||
-- http://www.eclipse.org/legal/epl-v10.html
|
||||
--
|
||||
-- This program and the accompanying materials are also made available
|
||||
-- under the terms of the MIT public license which accompanies this
|
||||
-- distribution, and is available at http://www.lua.org/license.html
|
||||
--
|
||||
-- Contributors:
|
||||
-- Fabien Fleutot - API and implementation
|
||||
--
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
--
|
||||
-- Summary: metalua parser, statement/block parser. This is part of the
|
||||
-- definition of module [mlp].
|
||||
--
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
--
|
||||
-- Exports API:
|
||||
-- * [mlp.stat()]
|
||||
-- * [mlp.block()]
|
||||
-- * [mlp.for_header()]
|
||||
--
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
local lexer = require 'metalua.grammar.lexer'
|
||||
local gg = require 'metalua.grammar.generator'
|
||||
|
||||
local annot = require 'metalua.compiler.parser.annot.generator'
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- List of all keywords that indicate the end of a statement block. Users are
|
||||
-- likely to extend this list when designing extensions.
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
||||
return function(M)
|
||||
local _M = gg.future(M)
|
||||
|
||||
M.block_terminators = { "else", "elseif", "end", "until", ")", "}", "]" }
|
||||
|
||||
-- FIXME: this must be handled from within GG!!!
|
||||
-- FIXME: there's no :add method in the list anyway. Added by gg.list?!
|
||||
function M.block_terminators :add(x)
|
||||
if type (x) == "table" then for _, y in ipairs(x) do self :add (y) end
|
||||
else table.insert (self, x) end
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
-- list of statements, possibly followed by semicolons
|
||||
----------------------------------------------------------------------------
|
||||
M.block = gg.list {
|
||||
name = "statements block",
|
||||
terminators = M.block_terminators,
|
||||
primary = function (lx)
|
||||
-- FIXME use gg.optkeyword()
|
||||
local x = M.stat (lx)
|
||||
if lx:is_keyword (lx:peek(), ";") then lx:next() end
|
||||
return x
|
||||
end }
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
-- Helper function for "return <expr_list>" parsing.
|
||||
-- Called when parsing return statements.
|
||||
-- The specific test for initial ";" is because it's not a block terminator,
|
||||
-- so without it gg.list would choke on "return ;" statements.
|
||||
-- We don't make a modified copy of block_terminators because this list
|
||||
-- is sometimes modified at runtime, and the return parser would get out of
|
||||
-- sync if it was relying on a copy.
|
||||
----------------------------------------------------------------------------
|
||||
local return_expr_list_parser = gg.multisequence{
|
||||
{ ";" , builder = function() return { } end },
|
||||
default = gg.list {
|
||||
_M.expr, separators = ",", terminators = M.block_terminators } }
|
||||
|
||||
|
||||
local for_vars_list = gg.list{
|
||||
name = "for variables list",
|
||||
primary = _M.id,
|
||||
separators = ",",
|
||||
terminators = "in" }
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
-- for header, between [for] and [do] (exclusive).
|
||||
-- Return the `Forxxx{...} AST, without the body element (the last one).
|
||||
----------------------------------------------------------------------------
|
||||
function M.for_header (lx)
|
||||
local vars = M.id_list(lx)
|
||||
if lx :is_keyword (lx:peek(), "=") then
|
||||
if #vars ~= 1 then
|
||||
gg.parse_error (lx, "numeric for only accepts one variable")
|
||||
end
|
||||
lx:next() -- skip "="
|
||||
local exprs = M.expr_list (lx)
|
||||
if #exprs < 2 or #exprs > 3 then
|
||||
gg.parse_error (lx, "numeric for requires 2 or 3 boundaries")
|
||||
end
|
||||
return { tag="Fornum", vars[1], unpack (exprs) }
|
||||
else
|
||||
if not lx :is_keyword (lx :next(), "in") then
|
||||
gg.parse_error (lx, '"=" or "in" expected in for loop')
|
||||
end
|
||||
local exprs = M.expr_list (lx)
|
||||
return { tag="Forin", vars, exprs }
|
||||
end
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
-- Function def parser helper: id ( . id ) *
|
||||
----------------------------------------------------------------------------
|
||||
local function fn_builder (list)
|
||||
local acc = list[1]
|
||||
local first = acc.lineinfo.first
|
||||
for i = 2, #list do
|
||||
local index = M.id2string(list[i])
|
||||
local li = lexer.new_lineinfo(first, index.lineinfo.last)
|
||||
acc = { tag="Index", acc, index, lineinfo=li }
|
||||
end
|
||||
return acc
|
||||
end
|
||||
local func_name = gg.list{ _M.id, separators = ".", builder = fn_builder }
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
-- Function def parser helper: ( : id )?
|
||||
----------------------------------------------------------------------------
|
||||
local method_name = gg.onkeyword{ name = "method invocation", ":", _M.id,
|
||||
transformers = { function(x) return x and x.tag=='Id' and M.id2string(x) end } }
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
-- Function def builder
|
||||
----------------------------------------------------------------------------
|
||||
local function funcdef_builder(x)
|
||||
local name, method, func = unpack(x)
|
||||
if method then
|
||||
name = { tag="Index", name, method,
|
||||
lineinfo = {
|
||||
first = name.lineinfo.first,
|
||||
last = method.lineinfo.last } }
|
||||
table.insert (func[1], 1, {tag="Id", "self"})
|
||||
end
|
||||
local r = { tag="Set", {name}, {func} }
|
||||
r[1].lineinfo = name.lineinfo
|
||||
r[2].lineinfo = func.lineinfo
|
||||
return r
|
||||
end
|
||||
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
-- if statement builder
|
||||
----------------------------------------------------------------------------
|
||||
local function if_builder (x)
|
||||
local cond_block_pairs, else_block, r = x[1], x[2], {tag="If"}
|
||||
local n_pairs = #cond_block_pairs
|
||||
for i = 1, n_pairs do
|
||||
local cond, block = unpack(cond_block_pairs[i])
|
||||
r[2*i-1], r[2*i] = cond, block
|
||||
end
|
||||
if else_block then table.insert(r, #r+1, else_block) end
|
||||
return r
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- produce a list of (expr,block) pairs
|
||||
--------------------------------------------------------------------------------
|
||||
local elseifs_parser = gg.list {
|
||||
gg.sequence { _M.expr, "then", _M.block , name='elseif parser' },
|
||||
separators = "elseif",
|
||||
terminators = { "else", "end" }
|
||||
}
|
||||
|
||||
local annot_expr = gg.sequence {
|
||||
_M.expr,
|
||||
gg.onkeyword{ "#", gg.future(M, 'annot').tf },
|
||||
builder = function(x)
|
||||
local e, a = unpack(x)
|
||||
if a then return { tag='Annot', e, a }
|
||||
else return e end
|
||||
end }
|
||||
|
||||
local annot_expr_list = gg.list {
|
||||
primary = annot.opt(M, _M.expr, 'tf'), separators = ',' }
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- assignments and calls: statements that don't start with a keyword
|
||||
------------------------------------------------------------------------
|
||||
local function assign_or_call_stat_parser (lx)
|
||||
local e = annot_expr_list (lx)
|
||||
local a = lx:is_keyword(lx:peek())
|
||||
local op = a and M.assignments[a]
|
||||
-- TODO: refactor annotations
|
||||
if op then
|
||||
--FIXME: check that [e] is a LHS
|
||||
lx :next()
|
||||
local annots
|
||||
e, annots = annot.split(e)
|
||||
local v = M.expr_list (lx)
|
||||
if type(op)=="string" then return { tag=op, e, v, annots }
|
||||
else return op (e, v) end
|
||||
else
|
||||
assert (#e > 0)
|
||||
if #e > 1 then
|
||||
gg.parse_error (lx,
|
||||
"comma is not a valid statement separator; statement can be "..
|
||||
"separated by semicolons, or not separated at all")
|
||||
elseif e[1].tag ~= "Call" and e[1].tag ~= "Invoke" then
|
||||
local typename
|
||||
if e[1].tag == 'Id' then
|
||||
typename = '("'..e[1][1]..'") is an identifier'
|
||||
elseif e[1].tag == 'Op' then
|
||||
typename = "is an arithmetic operation"
|
||||
else typename = "is of type '"..(e[1].tag or "<list>").."'" end
|
||||
gg.parse_error (lx,
|
||||
"This expression %s; "..
|
||||
"a statement was expected, and only function and method call "..
|
||||
"expressions can be used as statements", typename);
|
||||
end
|
||||
return e[1]
|
||||
end
|
||||
end
|
||||
|
||||
M.local_stat_parser = gg.multisequence{
|
||||
-- local function <name> <func_val>
|
||||
{ "function", _M.id, _M.func_val, builder =
|
||||
function(x)
|
||||
local vars = { x[1], lineinfo = x[1].lineinfo }
|
||||
local vals = { x[2], lineinfo = x[2].lineinfo }
|
||||
return { tag="Localrec", vars, vals }
|
||||
end },
|
||||
-- local <id_list> ( = <expr_list> )?
|
||||
default = gg.sequence{
|
||||
gg.list{
|
||||
primary = annot.opt(M, _M.id, 'tf'),
|
||||
separators = ',' },
|
||||
gg.onkeyword{ "=", _M.expr_list },
|
||||
builder = function(x)
|
||||
local annotated_left, right = unpack(x)
|
||||
local left, annotations = annot.split(annotated_left)
|
||||
return {tag="Local", left, right or { }, annotations }
|
||||
end } }
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- statement
|
||||
------------------------------------------------------------------------
|
||||
M.stat = gg.multisequence {
|
||||
name = "statement",
|
||||
{ "do", _M.block, "end", builder =
|
||||
function (x) return { tag="Do", unpack (x[1]) } end },
|
||||
{ "for", _M.for_header, "do", _M.block, "end", builder =
|
||||
function (x) x[1][#x[1]+1] = x[2]; return x[1] end },
|
||||
{ "function", func_name, method_name, _M.func_val, builder=funcdef_builder },
|
||||
{ "while", _M.expr, "do", _M.block, "end", builder = "While" },
|
||||
{ "repeat", _M.block, "until", _M.expr, builder = "Repeat" },
|
||||
{ "local", _M.local_stat_parser, builder = unpack },
|
||||
{ "return", return_expr_list_parser, builder =
|
||||
function(x) x[1].tag='Return'; return x[1] end },
|
||||
{ "break", builder = function() return { tag="Break" } end },
|
||||
{ "-{", gg.future(M, 'meta').splice_content, "}", builder = unpack },
|
||||
{ "if", gg.nonempty(elseifs_parser), gg.onkeyword{ "else", M.block }, "end",
|
||||
builder = if_builder },
|
||||
default = assign_or_call_stat_parser }
|
||||
|
||||
M.assignments = {
|
||||
["="] = "Set"
|
||||
}
|
||||
|
||||
function M.assignments:add(k, v) self[k] = v end
|
||||
|
||||
return M
|
||||
end
|
||||
77
lualibs/metalua/compiler/parser/table.lua
Normal file
77
lualibs/metalua/compiler/parser/table.lua
Normal file
@@ -0,0 +1,77 @@
|
||||
--------------------------------------------------------------------------------
|
||||
-- Copyright (c) 2006-2013 Fabien Fleutot and others.
|
||||
--
|
||||
-- All rights reserved.
|
||||
--
|
||||
-- This program and the accompanying materials are made available
|
||||
-- under the terms of the Eclipse Public License v1.0 which
|
||||
-- accompanies this distribution, and is available at
|
||||
-- http://www.eclipse.org/legal/epl-v10.html
|
||||
--
|
||||
-- This program and the accompanying materials are also made available
|
||||
-- under the terms of the MIT public license which accompanies this
|
||||
-- distribution, and is available at http://www.lua.org/license.html
|
||||
--
|
||||
-- Contributors:
|
||||
-- Fabien Fleutot - API and implementation
|
||||
--
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
--
|
||||
-- Exported API:
|
||||
-- * [M.table_bracket_field()]
|
||||
-- * [M.table_field()]
|
||||
-- * [M.table_content()]
|
||||
-- * [M.table()]
|
||||
--
|
||||
-- KNOWN BUG: doesn't handle final ";" or "," before final "}"
|
||||
--
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
local gg = require 'metalua.grammar.generator'
|
||||
|
||||
return function(M)
|
||||
|
||||
M.table = { }
|
||||
local _table = gg.future(M.table)
|
||||
local _expr = gg.future(M).expr
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- `[key] = value` table field definition
|
||||
--------------------------------------------------------------------------------
|
||||
M.table.bracket_pair = gg.sequence{ "[", _expr, "]", "=", _expr, builder = "Pair" }
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- table element parser: list value, `id = value` pair or `[value] = value` pair.
|
||||
--------------------------------------------------------------------------------
|
||||
function M.table.element (lx)
|
||||
if lx :is_keyword (lx :peek(), "[") then return M.table.bracket_pair(lx) end
|
||||
local e = M.expr (lx)
|
||||
if not lx :is_keyword (lx :peek(), "=") then return e end
|
||||
lx :next(); -- skip the "="
|
||||
local key = M.id2string(e) -- will fail on non-identifiers
|
||||
local val = M.expr(lx)
|
||||
local r = { tag="Pair", key, val }
|
||||
r.lineinfo = { first = key.lineinfo.first, last = val.lineinfo.last }
|
||||
return r
|
||||
end
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- table constructor, without enclosing braces; returns a full table object
|
||||
-----------------------------------------------------------------------------
|
||||
M.table.content = gg.list {
|
||||
-- eta expansion to allow patching the element definition
|
||||
primary = _table.element,
|
||||
separators = { ",", ";" },
|
||||
terminators = "}",
|
||||
builder = "Table" }
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- complete table constructor including [{...}]
|
||||
--------------------------------------------------------------------------------
|
||||
-- TODO beware, stat and expr use only table.content, this can't be patched.
|
||||
M.table.table = gg.sequence{ "{", _table.content, "}", builder = unpack }
|
||||
|
||||
return M
|
||||
end
|
||||
@@ -1,18 +1,29 @@
|
||||
----------------------------------------------------------------------
|
||||
-- Metalua.
|
||||
--------------------------------------------------------------------------------
|
||||
-- Copyright (c) 2006-2013 Fabien Fleutot and others.
|
||||
--
|
||||
-- All rights reserved.
|
||||
--
|
||||
-- This program and the accompanying materials are made available
|
||||
-- under the terms of the Eclipse Public License v1.0 which
|
||||
-- accompanies this distribution, and is available at
|
||||
-- http://www.eclipse.org/legal/epl-v10.html
|
||||
--
|
||||
-- This program and the accompanying materials are also made available
|
||||
-- under the terms of the MIT public license which accompanies this
|
||||
-- distribution, and is available at http://www.lua.org/license.html
|
||||
--
|
||||
-- Contributors:
|
||||
-- Fabien Fleutot - API and implementation
|
||||
--
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
--
|
||||
-- Summary: parser generator. Collection of higher order functors,
|
||||
-- which allow to build and combine parsers. Relies on a lexer
|
||||
-- that supports the same API as the one exposed in mll.lua.
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
--
|
||||
-- Copyright (c) 2006-2008, Fabien Fleutot <metalua@gmail.com>.
|
||||
--
|
||||
-- This software is released under the MIT Licence, see licence.txt
|
||||
-- for details.
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
--
|
||||
@@ -26,48 +37,46 @@
|
||||
-- * [gg.onkeyword()]
|
||||
-- * [gg.optkeyword()]
|
||||
--
|
||||
-- Other functions:
|
||||
-- Other functions:
|
||||
-- * [gg.parse_error()]
|
||||
-- * [gg.make_parser()]
|
||||
-- * [gg.is_parser()]
|
||||
--
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
module("gg", package.seeall)
|
||||
local M = { }
|
||||
|
||||
local lexer = require 'metalua.grammar.lexer'
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Symbol generator: [gensym()] returns a guaranteed-to-be-unique identifier.
|
||||
-- The main purpose is to avoid variable capture in macros.
|
||||
--
|
||||
-- If a string is passed as an argument, theis string will be part of the
|
||||
-- id name (helpful for macro debugging)
|
||||
--------------------------------------------------------------------------------
|
||||
local gensymidx = 0
|
||||
|
||||
function M.gensym (arg)
|
||||
gensymidx = gensymidx + 1
|
||||
return { tag="Id", string.format(".%i.%s", gensymidx, arg or "")}
|
||||
end
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- parser metatable, which maps __call to method parse, and adds some
|
||||
-- error tracing boilerplate.
|
||||
-------------------------------------------------------------------------------
|
||||
local parser_metatable = { }
|
||||
function parser_metatable.__call (parser, lx, ...)
|
||||
--printf ("Call parser %q of type %q", parser.name or "?", parser.kind)
|
||||
if mlc.metabugs then
|
||||
return parser:parse (lx, ...)
|
||||
--local x = parser:parse (lx, ...)
|
||||
--printf ("Result of parser %q: %s",
|
||||
-- parser.name or "?",
|
||||
-- _G.table.tostring(x, "nohash", 80))
|
||||
--return x
|
||||
else
|
||||
local li = lx:lineinfo_right() or { "?", "?", "?", "?" }
|
||||
local status, ast = pcall (parser.parse, parser, lx, ...)
|
||||
if status then return ast else
|
||||
-- Try to replace the gg.lua location, in the error msg, with
|
||||
-- the place where the current parser started handling the
|
||||
-- lexstream.
|
||||
-- Since the error is rethrown, these places are stacked.
|
||||
error (string.format ("%s\n - (l.%s, c.%s, k.%s) in parser %s",
|
||||
ast :strmatch "gg.lua:%d+: (.*)" or ast,
|
||||
li[1], li[2], li[3], parser.name or parser.kind))
|
||||
end
|
||||
end
|
||||
|
||||
function parser_metatable :__call (lx, ...)
|
||||
return self :parse (lx, ...)
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Turn a table into a parser, mainly by setting the metatable.
|
||||
-------------------------------------------------------------------------------
|
||||
function make_parser(kind, p)
|
||||
function M.make_parser(kind, p)
|
||||
p.kind = kind
|
||||
if not p.transformers then p.transformers = { } end
|
||||
function p.transformers:add (x)
|
||||
@@ -81,29 +90,32 @@ end
|
||||
-- Return true iff [x] is a parser.
|
||||
-- If it's a gg-generated parser, return the name of its kind.
|
||||
-------------------------------------------------------------------------------
|
||||
function is_parser (x)
|
||||
function M.is_parser (x)
|
||||
return type(x)=="function" or getmetatable(x)==parser_metatable and x.kind
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Parse a sequence, without applying builder nor transformers
|
||||
-- Parse a sequence, without applying builder nor transformers.
|
||||
-------------------------------------------------------------------------------
|
||||
local function raw_parse_sequence (lx, p)
|
||||
local r = { }
|
||||
for i=1, #p do
|
||||
e=p[i]
|
||||
if type(e) == "string" then
|
||||
if not lx:is_keyword (lx:next(), e) then
|
||||
parse_error (lx, "A keyword was expected, probably `%s'.", e) end
|
||||
elseif is_parser (e) then
|
||||
table.insert (r, e (lx))
|
||||
else
|
||||
gg.parse_error (lx,"Sequence `%s': element #%i is neither a string "..
|
||||
"nor a parser: %s",
|
||||
p.name, i, table.tostring(e))
|
||||
end
|
||||
end
|
||||
return r
|
||||
local r = { }
|
||||
for i=1, #p do
|
||||
local e=p[i]
|
||||
if type(e) == "string" then
|
||||
local kw = lx :next()
|
||||
if not lx :is_keyword (kw, e) then
|
||||
M.parse_error(
|
||||
lx, "A keyword was expected, probably `%s'.", e)
|
||||
end
|
||||
elseif M.is_parser (e) then
|
||||
table.insert (r, e(lx))
|
||||
else -- Invalid parser definition, this is *not* a parsing error
|
||||
error(string.format(
|
||||
"Sequence `%s': element #%i is neither a string nor a parser: %s",
|
||||
p.name, i, table.tostring(e)))
|
||||
end
|
||||
end
|
||||
return r
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
@@ -124,10 +136,10 @@ local function transform (ast, parser, fli, lli)
|
||||
if parser.transformers then
|
||||
for _, t in ipairs (parser.transformers) do ast = t(ast) or ast end
|
||||
end
|
||||
if type(ast) == 'table'then
|
||||
if type(ast) == 'table' then
|
||||
local ali = ast.lineinfo
|
||||
if not ali or ali.first~=fli or ali.last~=lli then
|
||||
ast.lineinfo = { first = fli, last = lli }
|
||||
ast.lineinfo = lexer.new_lineinfo(fli, lli)
|
||||
end
|
||||
end
|
||||
return ast
|
||||
@@ -136,21 +148,32 @@ end
|
||||
-------------------------------------------------------------------------------
|
||||
-- Generate a tracable parsing error (not implemented yet)
|
||||
-------------------------------------------------------------------------------
|
||||
function parse_error(lx, fmt, ...)
|
||||
local li = lx:lineinfo_left() or {-1,-1,-1, "<unknown file>"}
|
||||
local msg = string.format("line %i, char %i: "..fmt, li[1], li[2], ...)
|
||||
function M.parse_error(lx, fmt, ...)
|
||||
local li = lx:lineinfo_left()
|
||||
local file, line, column, offset, positions
|
||||
if li then
|
||||
file, line, column, offset = li.source, li.line, li.column, li.offset
|
||||
positions = { first = li, last = li }
|
||||
else
|
||||
line, column, offset = -1, -1, -1
|
||||
end
|
||||
|
||||
local msg = string.format("line %i, char %i: "..fmt, line, column, ...)
|
||||
if file and file~='?' then msg = "file "..file..", "..msg end
|
||||
|
||||
local src = lx.src
|
||||
if li[3]>0 and src then
|
||||
local i, j = li[3], li[3]
|
||||
if offset>0 and src then
|
||||
local i, j = offset, offset
|
||||
while src:sub(i,i) ~= '\n' and i>=0 do i=i-1 end
|
||||
while src:sub(j,j) ~= '\n' and j<=#src do j=j+1 end
|
||||
while src:sub(j,j) ~= '\n' and j<=#src do j=j+1 end
|
||||
local srcline = src:sub (i+1, j-1)
|
||||
local idx = string.rep (" ", li[2]).."^"
|
||||
local idx = string.rep (" ", column).."^"
|
||||
msg = string.format("%s\n>>> %s\n>>> %s", msg, srcline, idx)
|
||||
end
|
||||
--lx :kill()
|
||||
error(msg)
|
||||
end
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
--
|
||||
-- Sequence parser generator
|
||||
@@ -169,7 +192,7 @@ end
|
||||
-- * [transformers]: a list of AST->AST functions, applied in order on ASTs
|
||||
-- returned by the parser.
|
||||
--
|
||||
-- * Table-part entries corresponds to keywords (strings) and subparsers
|
||||
-- * Table-part entries corresponds to keywords (strings) and subparsers
|
||||
-- (function and callable objects).
|
||||
--
|
||||
-- After creation, the following fields are added:
|
||||
@@ -178,13 +201,14 @@ end
|
||||
-- * [name] is set, if it wasn't in the input.
|
||||
--
|
||||
-------------------------------------------------------------------------------
|
||||
function sequence (p)
|
||||
make_parser ("sequence", p)
|
||||
function M.sequence (p)
|
||||
M.make_parser ("sequence", p)
|
||||
|
||||
-------------------------------------------------------------------
|
||||
-- Parsing method
|
||||
-------------------------------------------------------------------
|
||||
function p:parse (lx)
|
||||
|
||||
-- Raw parsing:
|
||||
local fli = lx:lineinfo_right()
|
||||
local seq = raw_parse_sequence (lx, self)
|
||||
@@ -213,7 +237,7 @@ function sequence (p)
|
||||
p.name = p[1] .. " ... " .. p[#p]
|
||||
else p.name = p[1] .. " ..." end
|
||||
else -- can't find a decent name
|
||||
p.name = "<anonymous>"
|
||||
p.name = "unnamed_sequence"
|
||||
end
|
||||
|
||||
return p
|
||||
@@ -258,52 +282,50 @@ end --</sequence>
|
||||
-- * [kind] == "multisequence"
|
||||
--
|
||||
-------------------------------------------------------------------------------
|
||||
function multisequence (p)
|
||||
make_parser ("multisequence", p)
|
||||
function M.multisequence (p)
|
||||
M.make_parser ("multisequence", p)
|
||||
|
||||
-------------------------------------------------------------------
|
||||
-- Add a sequence (might be just a config table for [gg.sequence])
|
||||
-------------------------------------------------------------------
|
||||
function p:add (s)
|
||||
function p :add (s)
|
||||
-- compile if necessary:
|
||||
local keyword = type(s)=='table' and s[1]
|
||||
if type(s)=='table' and not is_parser(s) then sequence(s) end
|
||||
if is_parser(s)~='sequence' or type(keyword)~='string' then
|
||||
if type(s)=='table' and not M.is_parser(s) then M.sequence(s) end
|
||||
if M.is_parser(s)~='sequence' or type(keyword)~='string' then
|
||||
if self.default then -- two defaults
|
||||
error ("In a multisequence parser, all but one sequences "..
|
||||
"must start with a keyword")
|
||||
else self.default = s end -- first default
|
||||
elseif self.sequences[keyword] then -- duplicate keyword
|
||||
eprintf (" *** Warning: keyword %q overloaded in multisequence ***",
|
||||
keyword)
|
||||
else
|
||||
if self.sequences[keyword] then -- duplicate keyword
|
||||
-- TODO: warn that initial keyword `keyword` is overloaded in multiseq
|
||||
end
|
||||
self.sequences[keyword] = s
|
||||
else -- newly caught keyword
|
||||
self.sequences[keyword] = s
|
||||
end
|
||||
end
|
||||
end -- </multisequence.add>
|
||||
|
||||
-------------------------------------------------------------------
|
||||
-- Get the sequence starting with this keyword. [kw :: string]
|
||||
-------------------------------------------------------------------
|
||||
function p:get (kw) return self.sequences [kw] end
|
||||
function p :get (kw) return self.sequences [kw] end
|
||||
|
||||
-------------------------------------------------------------------
|
||||
-- Remove the sequence starting with keyword [kw :: string]
|
||||
-------------------------------------------------------------------
|
||||
function p:del (kw)
|
||||
if not self.sequences[kw] then
|
||||
eprintf("*** Warning: trying to delete sequence starting "..
|
||||
"with %q from a multisequence having no such "..
|
||||
"entry ***", kw) end
|
||||
function p :del (kw)
|
||||
if not self.sequences[kw] then
|
||||
-- TODO: warn that we try to delete a non-existent entry
|
||||
end
|
||||
local removed = self.sequences[kw]
|
||||
self.sequences[kw] = nil
|
||||
self.sequences[kw] = nil
|
||||
return removed
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------
|
||||
-- Parsing method
|
||||
-------------------------------------------------------------------
|
||||
function p:parse (lx)
|
||||
function p :parse (lx)
|
||||
local fli = lx:lineinfo_right()
|
||||
local x = raw_parse_multisequence (lx, self.sequences, self.default)
|
||||
local lli = lx:lineinfo_left()
|
||||
@@ -317,7 +339,7 @@ function multisequence (p)
|
||||
-- from the array part of the parser to the hash part of field
|
||||
-- [sequences]
|
||||
p.sequences = { }
|
||||
for i=1, #p do p:add (p[i]); p[i] = nil end
|
||||
for i=1, #p do p :add (p[i]); p[i] = nil end
|
||||
|
||||
-- FIXME: why is this commented out?
|
||||
--if p.default and not is_parser(p.default) then sequence(p.default) end
|
||||
@@ -342,9 +364,9 @@ end --</multisequence>
|
||||
-- * the builder takes specific parameters:
|
||||
-- - for [prefix], it takes the result of the prefix sequence parser,
|
||||
-- and the prefixed expression
|
||||
-- - for [infix], it takes the left-hand-side expression, the results
|
||||
-- - for [infix], it takes the left-hand-side expression, the results
|
||||
-- of the infix sequence parser, and the right-hand-side expression.
|
||||
-- - for [suffix], it takes the suffixed expression, and theresult
|
||||
-- - for [suffix], it takes the suffixed expression, and the result
|
||||
-- of the suffix sequence parser.
|
||||
--
|
||||
-- * the default field is a list, with parameters:
|
||||
@@ -357,7 +379,7 @@ end --</multisequence>
|
||||
-- In [p], useful fields are:
|
||||
-- * [transformers]: as usual
|
||||
-- * [name]: as usual
|
||||
-- * [primary]: the atomic expression parser, or a multisequence config
|
||||
-- * [primary]: the atomic expression parser, or a multisequence config
|
||||
-- table (mandatory)
|
||||
-- * [prefix]: prefix operators config table, see above.
|
||||
-- * [infix]: infix operators config table, see above.
|
||||
@@ -366,12 +388,12 @@ end --</multisequence>
|
||||
-- After creation, these fields are added:
|
||||
-- * [kind] == "expr"
|
||||
-- * [parse] as usual
|
||||
-- * each table is turned into a multisequence, and therefore has an
|
||||
-- * each table is turned into a multisequence, and therefore has an
|
||||
-- [add] method
|
||||
--
|
||||
-------------------------------------------------------------------------------
|
||||
function expr (p)
|
||||
make_parser ("expr", p)
|
||||
function M.expr (p)
|
||||
M.make_parser ("expr", p)
|
||||
|
||||
-------------------------------------------------------------------
|
||||
-- parser method.
|
||||
@@ -379,7 +401,7 @@ function expr (p)
|
||||
-- it won't read expressions whose precedence is lower or equal
|
||||
-- to [prec].
|
||||
-------------------------------------------------------------------
|
||||
function p:parse (lx, prec)
|
||||
function p :parse (lx, prec)
|
||||
prec = prec or 0
|
||||
|
||||
------------------------------------------------------
|
||||
@@ -388,7 +410,7 @@ function expr (p)
|
||||
-- Options include prec, assoc, transformers.
|
||||
------------------------------------------------------
|
||||
local function get_parser_info (tab)
|
||||
local p2 = tab:get (lx:is_keyword (lx:peek()))
|
||||
local p2 = tab :get (lx :is_keyword (lx :peek()))
|
||||
if p2 then -- keyword-based sequence found
|
||||
local function parser(lx) return raw_parse_sequence(lx, p2) end
|
||||
return parser, p2
|
||||
@@ -406,17 +428,17 @@ function expr (p)
|
||||
-- expr, and one for the one with the prefix op.
|
||||
------------------------------------------------------
|
||||
local function handle_prefix ()
|
||||
local fli = lx:lineinfo_right()
|
||||
local fli = lx :lineinfo_right()
|
||||
local p2_func, p2 = get_parser_info (self.prefix)
|
||||
local op = p2_func and p2_func (lx)
|
||||
if op then -- Keyword-based sequence found
|
||||
local ili = lx:lineinfo_right() -- Intermediate LineInfo
|
||||
local e = p2.builder (op, self:parse (lx, p2.prec))
|
||||
local lli = lx:lineinfo_left()
|
||||
local ili = lx :lineinfo_right() -- Intermediate LineInfo
|
||||
local e = p2.builder (op, self :parse (lx, p2.prec))
|
||||
local lli = lx :lineinfo_left()
|
||||
return transform (transform (e, p2, ili, lli), self, fli, lli)
|
||||
else -- No prefix found, get a primary expression
|
||||
else -- No prefix found, get a primary expression
|
||||
local e = self.primary(lx)
|
||||
local lli = lx:lineinfo_left()
|
||||
local lli = lx :lineinfo_left()
|
||||
return transform (e, self, fli, lli)
|
||||
end
|
||||
end --</expr.parse.handle_prefix>
|
||||
@@ -432,7 +454,7 @@ function expr (p)
|
||||
|
||||
-----------------------------------------
|
||||
-- Handle flattening operators: gather all operands
|
||||
-- of the series in [list]; when a different operator
|
||||
-- of the series in [list]; when a different operator
|
||||
-- is found, stop, build from [list], [transform] and
|
||||
-- return.
|
||||
-----------------------------------------
|
||||
@@ -449,13 +471,13 @@ function expr (p)
|
||||
local e2 = pflat.builder (list)
|
||||
local lli = lx:lineinfo_left()
|
||||
return transform (transform (e2, pflat, fli, lli), self, fli, lli)
|
||||
|
||||
|
||||
-----------------------------------------
|
||||
-- Handle regular infix operators: [e] the LHS is known,
|
||||
-- just gather the operator and [e2] the RHS.
|
||||
-- Result goes in [e3].
|
||||
-----------------------------------------
|
||||
elseif p2.prec and p2.prec>prec or
|
||||
elseif p2.prec and p2.prec>prec or
|
||||
p2.prec==prec and p2.assoc=="right" then
|
||||
local fli = e.lineinfo.first -- lx:lineinfo_right()
|
||||
local op = p2_func(lx)
|
||||
@@ -466,10 +488,10 @@ function expr (p)
|
||||
return transform (transform (e3, p2, fli, lli), self, fli, lli)
|
||||
|
||||
-----------------------------------------
|
||||
-- Check for non-associative operators, and complain if applicable.
|
||||
-- Check for non-associative operators, and complain if applicable.
|
||||
-----------------------------------------
|
||||
elseif p2.assoc=="none" and p2.prec==prec then
|
||||
parse_error (lx, "non-associative operator!")
|
||||
M.parse_error (lx, "non-associative operator!")
|
||||
|
||||
-----------------------------------------
|
||||
-- No infix operator suitable at that precedence
|
||||
@@ -501,7 +523,7 @@ function expr (p)
|
||||
end --</expr.parse.handle_suffix>
|
||||
|
||||
------------------------------------------------------
|
||||
-- Parser body: read suffix and (infix+operand)
|
||||
-- Parser body: read suffix and (infix+operand)
|
||||
-- extensions as long as we're able to fetch more at
|
||||
-- this precedence level.
|
||||
------------------------------------------------------
|
||||
@@ -521,7 +543,7 @@ function expr (p)
|
||||
if not p.primary then p.primary=p[1]; p[1]=nil end
|
||||
for _, t in ipairs{ "primary", "prefix", "infix", "suffix" } do
|
||||
if not p[t] then p[t] = { } end
|
||||
if not is_parser(p[t]) then multisequence(p[t]) end
|
||||
if not M.is_parser(p[t]) then M.multisequence(p[t]) end
|
||||
end
|
||||
function p:add(...) return self.primary:add(...) end
|
||||
return p
|
||||
@@ -558,40 +580,43 @@ end --</expr>
|
||||
-- * [kind] == "list"
|
||||
--
|
||||
-------------------------------------------------------------------------------
|
||||
function list (p)
|
||||
make_parser ("list", p)
|
||||
function M.list (p)
|
||||
M.make_parser ("list", p)
|
||||
|
||||
-------------------------------------------------------------------
|
||||
-- Parsing method
|
||||
-------------------------------------------------------------------
|
||||
function p:parse (lx)
|
||||
function p :parse (lx)
|
||||
|
||||
------------------------------------------------------
|
||||
-- Used to quickly check whether there's a terminator
|
||||
-- Used to quickly check whether there's a terminator
|
||||
-- or a separator immediately ahead
|
||||
------------------------------------------------------
|
||||
local function peek_is_in (keywords)
|
||||
local function peek_is_in (keywords)
|
||||
return keywords and lx:is_keyword(lx:peek(), unpack(keywords)) end
|
||||
|
||||
local x = { }
|
||||
local fli = lx:lineinfo_right()
|
||||
local fli = lx :lineinfo_right()
|
||||
|
||||
-- if there's a terminator to start with, don't bother trying
|
||||
if not peek_is_in (self.terminators) then
|
||||
repeat table.insert (x, self.primary (lx)) -- read one element
|
||||
local is_empty_list = self.terminators and (peek_is_in (self.terminators) or lx:peek().tag=="Eof")
|
||||
if not is_empty_list then
|
||||
repeat
|
||||
local item = self.primary(lx)
|
||||
table.insert (x, item) -- read one element
|
||||
until
|
||||
-- First reason to stop: There's a separator list specified,
|
||||
-- and next token isn't one. Otherwise, consume it with [lx:next()]
|
||||
-- There's a separator list specified, and next token isn't in it.
|
||||
-- Otherwise, consume it with [lx:next()]
|
||||
self.separators and not(peek_is_in (self.separators) and lx:next()) or
|
||||
-- Other reason to stop: terminator token ahead
|
||||
-- Terminator token ahead
|
||||
peek_is_in (self.terminators) or
|
||||
-- Last reason: end of file reached
|
||||
lx:peek().tag=="Eof"
|
||||
end
|
||||
|
||||
local lli = lx:lineinfo_left()
|
||||
|
||||
-- Apply the builder. It can be a string, or a callable value,
|
||||
|
||||
-- Apply the builder. It can be a string, or a callable value,
|
||||
-- or simply nothing.
|
||||
local b = self.builder
|
||||
if b then
|
||||
@@ -620,10 +645,10 @@ end --</list>
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
--
|
||||
-- Keyword-conditionned parser generator
|
||||
-- Keyword-conditioned parser generator
|
||||
--
|
||||
-------------------------------------------------------------------------------
|
||||
--
|
||||
--
|
||||
-- Only apply a parser if a given keyword is found. The result of
|
||||
-- [gg.onkeyword] parser is the result of the subparser (modulo
|
||||
-- [transformers] applications).
|
||||
@@ -639,10 +664,10 @@ end --</list>
|
||||
--
|
||||
-- * [transformers]: as usual
|
||||
--
|
||||
-- * [peek]: if non-nil, the conditionning keyword is left in the lexeme
|
||||
-- * [peek]: if non-nil, the conditioning keyword is left in the lexeme
|
||||
-- stream instead of being consumed.
|
||||
--
|
||||
-- * [primary]: the subparser.
|
||||
-- * [primary]: the subparser.
|
||||
--
|
||||
-- * [keywords]: list of strings representing triggering keywords.
|
||||
--
|
||||
@@ -650,26 +675,27 @@ end --</list>
|
||||
-- Strings are put in [keywords], and the parser is put in [primary].
|
||||
--
|
||||
-- After the call, the following fields will be set:
|
||||
--
|
||||
--
|
||||
-- * [parse] the parsing method
|
||||
-- * [kind] == "onkeyword"
|
||||
-- * [primary]
|
||||
-- * [keywords]
|
||||
--
|
||||
-------------------------------------------------------------------------------
|
||||
function onkeyword (p)
|
||||
make_parser ("onkeyword", p)
|
||||
function M.onkeyword (p)
|
||||
M.make_parser ("onkeyword", p)
|
||||
|
||||
-------------------------------------------------------------------
|
||||
-- Parsing method
|
||||
-------------------------------------------------------------------
|
||||
function p:parse(lx)
|
||||
if lx:is_keyword (lx:peek(), unpack(self.keywords)) then
|
||||
--local fli = lx:lineinfo_right()
|
||||
function p :parse (lx)
|
||||
if lx :is_keyword (lx:peek(), unpack(self.keywords)) then
|
||||
local fli = lx:lineinfo_right()
|
||||
if not self.peek then lx:next() end
|
||||
local content = self.primary (lx)
|
||||
--local lli = lx:lineinfo_left()
|
||||
local fli, lli = content.lineinfo.first, content.lineinfo.last
|
||||
local lli = lx:lineinfo_left()
|
||||
local li = content.lineinfo or { }
|
||||
fli, lli = li.first or fli, li.last or lli
|
||||
return transform (content, p, fli, lli)
|
||||
else return false end
|
||||
end
|
||||
@@ -680,10 +706,9 @@ function onkeyword (p)
|
||||
if not p.keywords then p.keywords = { } end
|
||||
for _, x in ipairs(p) do
|
||||
if type(x)=="string" then table.insert (p.keywords, x)
|
||||
else assert (not p.primary and is_parser (x)); p.primary = x end
|
||||
else assert (not p.primary and M.is_parser (x)); p.primary = x end
|
||||
end
|
||||
if not next (p.keywords) then
|
||||
eprintf("Warning, no keyword to trigger gg.onkeyword") end
|
||||
assert (next (p.keywords), "Missing trigger keyword in gg.onkeyword")
|
||||
assert (p.primary, 'no primary parser in gg.onkeyword')
|
||||
return p
|
||||
end --</onkeyword>
|
||||
@@ -696,15 +721,15 @@ end --</onkeyword>
|
||||
-------------------------------------------------------------------------------
|
||||
--
|
||||
-- This doesn't return a real parser, just a function. That function parses
|
||||
-- one of the keywords passed as parameters, and returns it. It returns
|
||||
-- one of the keywords passed as parameters, and returns it. It returns
|
||||
-- [false] if no matching keyword is found.
|
||||
--
|
||||
-- Notice that tokens returned by lexer already carry lineinfo, therefore
|
||||
-- there's no need to add them, as done usually through transform() calls.
|
||||
-------------------------------------------------------------------------------
|
||||
function optkeyword (...)
|
||||
function M.optkeyword (...)
|
||||
local args = {...}
|
||||
if type (args[1]) == "table" then
|
||||
if type (args[1]) == "table" then
|
||||
assert (#args == 1)
|
||||
args = args[1]
|
||||
end
|
||||
@@ -729,15 +754,15 @@ end
|
||||
-- The resulting parser returns whatever the argument parser does.
|
||||
--
|
||||
-------------------------------------------------------------------------------
|
||||
function with_lexer(new_lexer, parser)
|
||||
function M.with_lexer(new_lexer, parser)
|
||||
|
||||
-------------------------------------------------------------------
|
||||
-- Most gg functions take their parameters in a table, so it's
|
||||
-- Most gg functions take their parameters in a table, so it's
|
||||
-- better to silently accept when with_lexer{ } is called with
|
||||
-- its arguments in a list:
|
||||
-------------------------------------------------------------------
|
||||
if not parser and #new_lexer==2 and type(new_lexer[1])=='table' then
|
||||
return with_lexer(unpack(new_lexer))
|
||||
return M.with_lexer(unpack(new_lexer))
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------
|
||||
@@ -754,3 +779,54 @@ function with_lexer(new_lexer, parser)
|
||||
if status then return result else error(result) end
|
||||
end
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
--
|
||||
-- Make sure a parser is used and returns successfully.
|
||||
--
|
||||
--------------------------------------------------------------------------------
|
||||
function M.nonempty(primary)
|
||||
local p = M.make_parser('non-empty list', { primary = primary, name=primary.name })
|
||||
function p :parse (lx)
|
||||
local fli = lx:lineinfo_right()
|
||||
local content = self.primary (lx)
|
||||
local lli = lx:lineinfo_left()
|
||||
local li = content.lineinfo or { }
|
||||
fli, lli = li.first or fli, li.last or lli
|
||||
if #content == 0 then
|
||||
M.parse_error (lx, "`%s' must not be empty.", self.name or "list")
|
||||
else
|
||||
return transform (content, self, fli, lli)
|
||||
end
|
||||
end
|
||||
return p
|
||||
end
|
||||
|
||||
local FUTURE_MT = { }
|
||||
function FUTURE_MT:__tostring() return "<Proxy parser module>" end
|
||||
function FUTURE_MT:__newindex(key, value) error "don't write in futures" end
|
||||
function FUTURE_MT :__index (parser_name)
|
||||
return function(...)
|
||||
local p, m = rawget(self, '__path'), self.__module
|
||||
if p then for _, name in ipairs(p) do
|
||||
m=rawget(m, name)
|
||||
if not m then error ("Submodule '"..name.."' undefined") end
|
||||
end end
|
||||
local f = rawget(m, parser_name)
|
||||
if not f then error ("Parser '"..parser_name.."' undefined") end
|
||||
return f(...)
|
||||
end
|
||||
end
|
||||
|
||||
function M.future(module, ...)
|
||||
checks('table')
|
||||
local path = ... and {...}
|
||||
if path then for _, x in ipairs(path) do
|
||||
assert(type(x)=='string', "Bad future arg")
|
||||
end end
|
||||
local self = { __module = module,
|
||||
__path = path }
|
||||
return setmetatable(self, FUTURE_MT)
|
||||
end
|
||||
|
||||
return M
|
||||
672
lualibs/metalua/grammar/lexer.lua
Normal file
672
lualibs/metalua/grammar/lexer.lua
Normal file
@@ -0,0 +1,672 @@
|
||||
-------------------------------------------------------------------------------
|
||||
-- Copyright (c) 2006-2013 Fabien Fleutot and others.
|
||||
--
|
||||
-- All rights reserved.
|
||||
--
|
||||
-- This program and the accompanying materials are made available
|
||||
-- under the terms of the Eclipse Public License v1.0 which
|
||||
-- accompanies this distribution, and is available at
|
||||
-- http://www.eclipse.org/legal/epl-v10.html
|
||||
--
|
||||
-- This program and the accompanying materials are also made available
|
||||
-- under the terms of the MIT public license which accompanies this
|
||||
-- distribution, and is available at http://www.lua.org/license.html
|
||||
--
|
||||
-- Contributors:
|
||||
-- Fabien Fleutot - API and implementation
|
||||
--
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
require 'checks'
|
||||
|
||||
local M = { }
|
||||
|
||||
local lexer = { alpha={ }, sym={ } }
|
||||
lexer.__index=lexer
|
||||
lexer.__type='lexer.stream'
|
||||
|
||||
M.lexer = lexer
|
||||
|
||||
|
||||
local debugf = function() end
|
||||
-- local debugf=printf
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- Some locale settings produce bad results, e.g. French locale
|
||||
-- expect float numbers to use commas instead of periods.
|
||||
-- TODO: change number parser into something loclae-independent,
|
||||
-- locales are nasty.
|
||||
----------------------------------------------------------------------
|
||||
os.setlocale('C')
|
||||
|
||||
local MT = { }
|
||||
|
||||
M.metatables=MT
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- Create a new metatable, for a new class of objects.
|
||||
----------------------------------------------------------------------
|
||||
local function new_metatable(name)
|
||||
local mt = { __type = 'lexer.'..name };
|
||||
mt.__index = mt
|
||||
MT[name] = mt
|
||||
end
|
||||
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- Position: represent a point in a source file.
|
||||
----------------------------------------------------------------------
|
||||
new_metatable 'position'
|
||||
|
||||
local position_idx=1
|
||||
|
||||
function M.new_position(line, column, offset, source)
|
||||
checks('number', 'number', 'number', 'string')
|
||||
local id = position_idx; position_idx = position_idx+1
|
||||
return setmetatable({line=line, column=column, offset=offset,
|
||||
source=source, id=id}, MT.position)
|
||||
end
|
||||
|
||||
function MT.position :__tostring()
|
||||
return string.format("<%s%s|L%d|C%d|K%d>",
|
||||
self.comments and "C|" or "",
|
||||
self.source, self.line, self.column, self.offset)
|
||||
end
|
||||
|
||||
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- Position factory: convert offsets into line/column/offset positions.
|
||||
----------------------------------------------------------------------
|
||||
new_metatable 'position_factory'
|
||||
|
||||
function M.new_position_factory(src, src_name)
|
||||
-- assert(type(src)=='string')
|
||||
-- assert(type(src_name)=='string')
|
||||
local lines = { 1 }
|
||||
for offset in src :gmatch '\n()' do table.insert(lines, offset) end
|
||||
local max = #src+1
|
||||
table.insert(lines, max+1) -- +1 includes Eof
|
||||
return setmetatable({ src_name=src_name, line2offset=lines, max=max },
|
||||
MT.position_factory)
|
||||
end
|
||||
|
||||
function MT.position_factory :get_position (offset)
|
||||
-- assert(type(offset)=='number')
|
||||
assert(offset<=self.max)
|
||||
local line2offset = self.line2offset
|
||||
local left = self.last_left or 1
|
||||
if offset<line2offset[left] then left=1 end
|
||||
local right = left+1
|
||||
if line2offset[right]<=offset then right = right+1 end
|
||||
if line2offset[right]<=offset then right = #line2offset end
|
||||
while true do
|
||||
-- print (" trying lines "..left.."/"..right..", offsets "..line2offset[left]..
|
||||
-- "/"..line2offset[right].." for offset "..offset)
|
||||
-- assert(line2offset[left]<=offset)
|
||||
-- assert(offset<line2offset[right])
|
||||
-- assert(left<right)
|
||||
if left+1==right then break end
|
||||
local middle = math.floor((left+right)/2)
|
||||
if line2offset[middle]<=offset then left=middle else right=middle end
|
||||
end
|
||||
-- assert(left+1==right)
|
||||
-- printf("found that offset %d is between %d and %d, hence on line %d",
|
||||
-- offset, line2offset[left], line2offset[right], left)
|
||||
local line = left
|
||||
local column = offset - line2offset[line] + 1
|
||||
self.last_left = left
|
||||
return M.new_position(line, column, offset, self.src_name)
|
||||
end
|
||||
|
||||
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- Lineinfo: represent a node's range in a source file;
|
||||
-- embed information about prefix and suffix comments.
|
||||
----------------------------------------------------------------------
|
||||
new_metatable 'lineinfo'
|
||||
|
||||
function M.new_lineinfo(first, last)
|
||||
checks('lexer.position', 'lexer.position')
|
||||
return setmetatable({first=first, last=last}, MT.lineinfo)
|
||||
end
|
||||
|
||||
function MT.lineinfo :__tostring()
|
||||
local fli, lli = self.first, self.last
|
||||
local line = fli.line; if line~=lli.line then line =line ..'-'..lli.line end
|
||||
local column = fli.column; if column~=lli.column then column=column..'-'..lli.column end
|
||||
local offset = fli.offset; if offset~=lli.offset then offset=offset..'-'..lli.offset end
|
||||
return string.format("<%s%s|L%s|C%s|K%s%s>",
|
||||
fli.comments and "C|" or "",
|
||||
fli.source, line, column, offset,
|
||||
lli.comments and "|C" or "")
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- Token: atomic Lua language element, with a category, a content,
|
||||
-- and some lineinfo relating it to its original source.
|
||||
----------------------------------------------------------------------
|
||||
new_metatable 'token'
|
||||
|
||||
function M.new_token(tag, content, lineinfo)
|
||||
--printf("TOKEN `%s{ %q, lineinfo = %s} boundaries %d, %d",
|
||||
-- tag, content, tostring(lineinfo), lineinfo.first.id, lineinfo.last.id)
|
||||
return setmetatable({tag=tag, lineinfo=lineinfo, content}, MT.token)
|
||||
end
|
||||
|
||||
function MT.token :__tostring()
|
||||
--return string.format("`%s{ %q, %s }", self.tag, self[1], tostring(self.lineinfo))
|
||||
return string.format("`%s %q", self.tag, self[1])
|
||||
end
|
||||
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- Comment: series of comment blocks with associated lineinfo.
|
||||
-- To be attached to the tokens just before and just after them.
|
||||
----------------------------------------------------------------------
|
||||
new_metatable 'comment'
|
||||
|
||||
function M.new_comment(lines)
|
||||
local first = lines[1].lineinfo.first
|
||||
local last = lines[#lines].lineinfo.last
|
||||
local lineinfo = M.new_lineinfo(first, last)
|
||||
return setmetatable({lineinfo=lineinfo, unpack(lines)}, MT.comment)
|
||||
end
|
||||
|
||||
function MT.comment :text()
|
||||
local last_line = self[1].lineinfo.last.line
|
||||
local acc = { }
|
||||
for i, line in ipairs(self) do
|
||||
local nreturns = line.lineinfo.first.line - last_line
|
||||
table.insert(acc, ("\n"):rep(nreturns))
|
||||
table.insert(acc, line[1])
|
||||
end
|
||||
return table.concat(acc)
|
||||
end
|
||||
|
||||
function M.new_comment_line(text, lineinfo, nequals)
|
||||
checks('string', 'lexer.lineinfo', '?number')
|
||||
return { lineinfo = lineinfo, text, nequals }
|
||||
end
|
||||
|
||||
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- Patterns used by [lexer :extract] to decompose the raw string into
|
||||
-- correctly tagged tokens.
|
||||
----------------------------------------------------------------------
|
||||
lexer.patterns = {
|
||||
spaces = "^[ \r\n\t]*()",
|
||||
short_comment = "^%-%-([^\n]*)\n?()",
|
||||
--final_short_comment = "^%-%-([^\n]*)()$",
|
||||
long_comment = "^%-%-%[(=*)%[\n?(.-)%]%1%]()",
|
||||
long_string = "^%[(=*)%[\n?(.-)%]%1%]()",
|
||||
number_mantissa = { "^%d+%.?%d*()", "^%d*%.%d+()" },
|
||||
number_mantissa_hex = { "^%x+%.?%x*()", "^%x*%.%x+()" }, --Lua5.1 and Lua5.2
|
||||
number_exponant = "^[eE][%+%-]?%d+()",
|
||||
number_exponant_hex = "^[pP][%+%-]?%d+()", --Lua5.2
|
||||
number_hex = "^0[xX]()",
|
||||
word = "^([%a_][%w_]*)()"
|
||||
}
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- unescape a whole string, applying [unesc_digits] and
|
||||
-- [unesc_letter] as many times as required.
|
||||
----------------------------------------------------------------------
|
||||
local function unescape_string (s)
|
||||
|
||||
-- Turn the digits of an escape sequence into the corresponding
|
||||
-- character, e.g. [unesc_digits("123") == string.char(123)].
|
||||
local function unesc_digits (backslashes, digits)
|
||||
if #backslashes%2==0 then
|
||||
-- Even number of backslashes, they escape each other, not the digits.
|
||||
-- Return them so that unesc_letter() can treat them
|
||||
return backslashes..digits
|
||||
else
|
||||
-- Remove the odd backslash, which escapes the number sequence.
|
||||
-- The rest will be returned and parsed by unesc_letter()
|
||||
backslashes = backslashes :sub (1,-2)
|
||||
end
|
||||
local k, j, i = digits :reverse() :byte(1, 3)
|
||||
local z = string.byte "0"
|
||||
local code = (k or z) + 10*(j or z) + 100*(i or z) - 111*z
|
||||
if code > 255 then
|
||||
error ("Illegal escape sequence '\\"..digits..
|
||||
"' in string: ASCII codes must be in [0..255]")
|
||||
end
|
||||
local c = string.char (code)
|
||||
if c == '\\' then c = '\\\\' end -- parsed by unesc_letter (test: "\092b" --> "\\b")
|
||||
return backslashes..c
|
||||
end
|
||||
|
||||
-- Turn hex digits of escape sequence into char.
|
||||
local function unesc_hex(backslashes, digits)
|
||||
if #backslashes%2==0 then
|
||||
return backslashes..'x'..digits
|
||||
else
|
||||
backslashes = backslashes :sub (1,-2)
|
||||
end
|
||||
local c = string.char(tonumber(digits,16))
|
||||
if c == '\\' then c = '\\\\' end -- parsed by unesc_letter (test: "\x5cb" --> "\\b")
|
||||
return backslashes..c
|
||||
end
|
||||
|
||||
-- Handle Lua 5.2 \z sequences
|
||||
local function unesc_z(backslashes, more)
|
||||
if #backslashes%2==0 then
|
||||
return backslashes..more
|
||||
else
|
||||
return backslashes :sub (1,-2)
|
||||
end
|
||||
end
|
||||
|
||||
-- Take a letter [x], and returns the character represented by the
|
||||
-- sequence ['\\'..x], e.g. [unesc_letter "n" == "\n"].
|
||||
local function unesc_letter(x)
|
||||
local t = {
|
||||
a = "\a", b = "\b", f = "\f",
|
||||
n = "\n", r = "\r", t = "\t", v = "\v",
|
||||
["\\"] = "\\", ["'"] = "'", ['"'] = '"', ["\n"] = "\n" }
|
||||
return t[x] or x
|
||||
end
|
||||
|
||||
s = s: gsub ("(\\+)(z%s*)", unesc_z) -- Lua 5.2
|
||||
s = s: gsub ("(\\+)([0-9][0-9]?[0-9]?)", unesc_digits)
|
||||
s = s: gsub ("(\\+)x([0-9a-fA-F][0-9a-fA-F])", unesc_hex) -- Lua 5.2
|
||||
s = s: gsub ("\\(%D)",unesc_letter)
|
||||
return s
|
||||
end
|
||||
|
||||
lexer.extractors = {
|
||||
"extract_long_comment", "extract_short_comment",
|
||||
"extract_short_string", "extract_word", "extract_number",
|
||||
"extract_long_string", "extract_symbol" }
|
||||
|
||||
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- Really extract next token from the raw string
|
||||
-- (and update the index).
|
||||
-- loc: offset of the position just after spaces and comments
|
||||
-- previous_i: offset in src before extraction began
|
||||
----------------------------------------------------------------------
|
||||
function lexer :extract ()
|
||||
local attached_comments = { }
|
||||
local function gen_token(...)
|
||||
local token = M.new_token(...)
|
||||
if #attached_comments>0 then -- attach previous comments to token
|
||||
local comments = M.new_comment(attached_comments)
|
||||
token.lineinfo.first.comments = comments
|
||||
if self.lineinfo_last_extracted then
|
||||
self.lineinfo_last_extracted.comments = comments
|
||||
end
|
||||
attached_comments = { }
|
||||
end
|
||||
token.lineinfo.first.facing = self.lineinfo_last_extracted
|
||||
self.lineinfo_last_extracted.facing = assert(token.lineinfo.first)
|
||||
self.lineinfo_last_extracted = assert(token.lineinfo.last)
|
||||
return token
|
||||
end
|
||||
while true do -- loop until a non-comment token is found
|
||||
|
||||
-- skip whitespaces
|
||||
self.i = self.src:match (self.patterns.spaces, self.i)
|
||||
if self.i>#self.src then
|
||||
local fli = self.posfact :get_position (#self.src+1)
|
||||
local lli = self.posfact :get_position (#self.src+1) -- ok?
|
||||
local tok = gen_token("Eof", "eof", M.new_lineinfo(fli, lli))
|
||||
tok.lineinfo.last.facing = lli
|
||||
return tok
|
||||
end
|
||||
local i_first = self.i -- loc = position after whitespaces
|
||||
|
||||
-- try every extractor until a token is found
|
||||
for _, extractor in ipairs(self.extractors) do
|
||||
local tag, content, xtra = self [extractor] (self)
|
||||
if tag then
|
||||
local fli = self.posfact :get_position (i_first)
|
||||
local lli = self.posfact :get_position (self.i-1)
|
||||
local lineinfo = M.new_lineinfo(fli, lli)
|
||||
if tag=='Comment' then
|
||||
local prev_comment = attached_comments[#attached_comments]
|
||||
if not xtra -- new comment is short
|
||||
and prev_comment and not prev_comment[2] -- prev comment is short
|
||||
and prev_comment.lineinfo.last.line+1==fli.line then -- adjascent lines
|
||||
-- concat with previous comment
|
||||
prev_comment[1] = prev_comment[1].."\n"..content -- TODO quadratic, BAD!
|
||||
prev_comment.lineinfo.last = lli
|
||||
else -- accumulate comment
|
||||
local comment = M.new_comment_line(content, lineinfo, xtra)
|
||||
table.insert(attached_comments, comment)
|
||||
end
|
||||
break -- back to skipping spaces
|
||||
else -- not a comment: real token, then
|
||||
return gen_token(tag, content, lineinfo)
|
||||
end -- if token is a comment
|
||||
end -- if token found
|
||||
end -- for each extractor
|
||||
end -- while token is a comment
|
||||
end -- :extract()
|
||||
|
||||
|
||||
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- Extract a short comment.
|
||||
----------------------------------------------------------------------
|
||||
function lexer :extract_short_comment()
|
||||
-- TODO: handle final_short_comment
|
||||
local content, j = self.src :match (self.patterns.short_comment, self.i)
|
||||
if content then self.i=j; return 'Comment', content, nil end
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- Extract a long comment.
|
||||
----------------------------------------------------------------------
|
||||
function lexer :extract_long_comment()
|
||||
local equals, content, j = self.src:match (self.patterns.long_comment, self.i)
|
||||
if j then self.i = j; return "Comment", content, #equals end
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- Extract a '...' or "..." short string.
|
||||
----------------------------------------------------------------------
|
||||
function lexer :extract_short_string()
|
||||
local k = self.src :sub (self.i,self.i) -- first char
|
||||
if k~=[[']] and k~=[["]] then return end -- no match'
|
||||
local i = self.i + 1
|
||||
local j = i
|
||||
while true do
|
||||
local x,y; x, j, y = self.src :match ("([\\\r\n"..k.."])()(.?)", j) -- next interesting char
|
||||
if x == '\\' then
|
||||
if y == 'z' then -- Lua 5.2 \z
|
||||
j = self.src :match ("^%s*()", j+1)
|
||||
else
|
||||
j=j+1 -- escaped char
|
||||
end
|
||||
elseif x == k then break -- end of string
|
||||
else
|
||||
assert (not x or x=='\r' or x=='\n')
|
||||
return nil, 'Unterminated string'
|
||||
end
|
||||
end
|
||||
self.i = j
|
||||
|
||||
return 'String', unescape_string (self.src :sub (i,j-2))
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- Extract Id or Keyword.
|
||||
----------------------------------------------------------------------
|
||||
function lexer :extract_word()
|
||||
local word, j = self.src:match (self.patterns.word, self.i)
|
||||
if word then
|
||||
self.i = j
|
||||
return (self.alpha [word] and 'Keyword' or 'Id'), word
|
||||
end
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- Extract Number.
|
||||
----------------------------------------------------------------------
|
||||
function lexer :extract_number()
|
||||
local j = self.src:match(self.patterns.number_hex, self.i)
|
||||
if j then
|
||||
j = self.src:match (self.patterns.number_mantissa_hex[1], j) or
|
||||
self.src:match (self.patterns.number_mantissa_hex[2], j)
|
||||
if j then
|
||||
j = self.src:match (self.patterns.number_exponant_hex, j) or j
|
||||
end
|
||||
else
|
||||
j = self.src:match (self.patterns.number_mantissa[1], self.i) or
|
||||
self.src:match (self.patterns.number_mantissa[2], self.i)
|
||||
if j then
|
||||
j = self.src:match (self.patterns.number_exponant, j) or j
|
||||
end
|
||||
end
|
||||
if not j then return end
|
||||
-- Number found, interpret with tonumber() and return it
|
||||
local str = self.src:sub (self.i, j-1)
|
||||
-- :TODO: tonumber on Lua5.2 floating hex may or may not work on Lua5.1
|
||||
local n = tonumber (str)
|
||||
if not n then error(str.." is not a valid number according to tonumber()") end
|
||||
self.i = j
|
||||
return 'Number', n
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- Extract long string.
|
||||
----------------------------------------------------------------------
|
||||
function lexer :extract_long_string()
|
||||
local _, content, j = self.src :match (self.patterns.long_string, self.i)
|
||||
if j then self.i = j; return 'String', content end
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- Extract symbol.
|
||||
----------------------------------------------------------------------
|
||||
function lexer :extract_symbol()
|
||||
local k = self.src:sub (self.i,self.i)
|
||||
local symk = self.sym [k] -- symbols starting with `k`
|
||||
if not symk then
|
||||
self.i = self.i + 1
|
||||
return 'Keyword', k
|
||||
end
|
||||
for _, sym in pairs (symk) do
|
||||
if sym == self.src:sub (self.i, self.i + #sym - 1) then
|
||||
self.i = self.i + #sym
|
||||
return 'Keyword', sym
|
||||
end
|
||||
end
|
||||
self.i = self.i+1
|
||||
return 'Keyword', k
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- Add a keyword to the list of keywords recognized by the lexer.
|
||||
----------------------------------------------------------------------
|
||||
function lexer :add (w, ...)
|
||||
assert(not ..., "lexer :add() takes only one arg, although possibly a table")
|
||||
if type (w) == "table" then
|
||||
for _, x in ipairs (w) do self :add (x) end
|
||||
else
|
||||
if w:match (self.patterns.word .. "$") then self.alpha [w] = true
|
||||
elseif w:match "^%p%p+$" then
|
||||
local k = w:sub(1,1)
|
||||
local list = self.sym [k]
|
||||
if not list then list = { }; self.sym [k] = list end
|
||||
table.insert (list, w)
|
||||
elseif w:match "^%p$" then return
|
||||
else error "Invalid keyword" end
|
||||
end
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- Return the [n]th next token, without consuming it.
|
||||
-- [n] defaults to 1. If it goes pass the end of the stream, an EOF
|
||||
-- token is returned.
|
||||
----------------------------------------------------------------------
|
||||
function lexer :peek (n)
|
||||
if not n then n=1 end
|
||||
if n > #self.peeked then
|
||||
for i = #self.peeked+1, n do
|
||||
self.peeked [i] = self :extract()
|
||||
end
|
||||
end
|
||||
return self.peeked [n]
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- Return the [n]th next token, removing it as well as the 0..n-1
|
||||
-- previous tokens. [n] defaults to 1. If it goes pass the end of the
|
||||
-- stream, an EOF token is returned.
|
||||
----------------------------------------------------------------------
|
||||
function lexer :next (n)
|
||||
n = n or 1
|
||||
self :peek (n)
|
||||
local a
|
||||
for i=1,n do
|
||||
a = table.remove (self.peeked, 1)
|
||||
-- TODO: is this used anywhere? I think not. a.lineinfo.last may be nil.
|
||||
--self.lastline = a.lineinfo.last.line
|
||||
end
|
||||
self.lineinfo_last_consumed = a.lineinfo.last
|
||||
return a
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- Returns an object which saves the stream's current state.
|
||||
----------------------------------------------------------------------
|
||||
-- FIXME there are more fields than that to save
|
||||
function lexer :save () return { self.i; {unpack(self.peeked) } } end
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- Restore the stream's state, as saved by method [save].
|
||||
----------------------------------------------------------------------
|
||||
-- FIXME there are more fields than that to restore
|
||||
function lexer :restore (s) self.i=s[1]; self.peeked=s[2] end
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- Resynchronize: cancel any token in self.peeked, by emptying the
|
||||
-- list and resetting the indexes
|
||||
----------------------------------------------------------------------
|
||||
function lexer :sync()
|
||||
local p1 = self.peeked[1]
|
||||
if p1 then
|
||||
local li_first = p1.lineinfo.first
|
||||
if li_first.comments then li_first=li_first.comments.lineinfo.first end
|
||||
self.i = li_first.offset
|
||||
self.column_offset = self.i - li_first.column
|
||||
self.peeked = { }
|
||||
self.attached_comments = p1.lineinfo.first.comments or { }
|
||||
end
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- Take the source and offset of an old lexer.
|
||||
----------------------------------------------------------------------
|
||||
function lexer :takeover(old)
|
||||
self :sync(); old :sync()
|
||||
for _, field in ipairs{ 'i', 'src', 'attached_comments', 'posfact' } do
|
||||
self[field] = old[field]
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- Return the current position in the sources. This position is between
|
||||
-- two tokens, and can be within a space / comment area, and therefore
|
||||
-- have a non-null width. :lineinfo_left() returns the beginning of the
|
||||
-- separation area, :lineinfo_right() returns the end of that area.
|
||||
--
|
||||
-- ____ last consummed token ____ first unconsummed token
|
||||
-- / /
|
||||
-- XXXXX <spaces and comments> YYYYY
|
||||
-- \____ \____
|
||||
-- :lineinfo_left() :lineinfo_right()
|
||||
----------------------------------------------------------------------
|
||||
function lexer :lineinfo_right()
|
||||
return self :peek(1).lineinfo.first
|
||||
end
|
||||
|
||||
function lexer :lineinfo_left()
|
||||
return self.lineinfo_last_consumed
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- Create a new lexstream.
|
||||
----------------------------------------------------------------------
|
||||
function lexer :newstream (src_or_stream, name)
|
||||
name = name or "?"
|
||||
if type(src_or_stream)=='table' then -- it's a stream
|
||||
return setmetatable ({ }, self) :takeover (src_or_stream)
|
||||
elseif type(src_or_stream)=='string' then -- it's a source string
|
||||
local src = src_or_stream
|
||||
local pos1 = M.new_position(1, 1, 1, name)
|
||||
local stream = {
|
||||
src_name = name; -- Name of the file
|
||||
src = src; -- The source, as a single string
|
||||
peeked = { }; -- Already peeked, but not discarded yet, tokens
|
||||
i = 1; -- Character offset in src
|
||||
attached_comments = { },-- comments accumulator
|
||||
lineinfo_last_extracted = pos1,
|
||||
lineinfo_last_consumed = pos1,
|
||||
posfact = M.new_position_factory (src_or_stream, name)
|
||||
}
|
||||
setmetatable (stream, self)
|
||||
|
||||
-- Skip initial sharp-bang for Unix scripts
|
||||
-- FIXME: redundant with mlp.chunk()
|
||||
if src and src :match "^#!" then
|
||||
local endofline = src :find "\n"
|
||||
stream.i = endofline and (endofline + 1) or #src
|
||||
end
|
||||
return stream
|
||||
else
|
||||
assert(false, ":newstream() takes a source string or a stream, not a "..
|
||||
type(src_or_stream))
|
||||
end
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- If there's no ... args, return the token a (whose truth value is
|
||||
-- true) if it's a `Keyword{ }, or nil. If there are ... args, they
|
||||
-- have to be strings. if the token a is a keyword, and it's content
|
||||
-- is one of the ... args, then returns it (it's truth value is
|
||||
-- true). If no a keyword or not in ..., return nil.
|
||||
----------------------------------------------------------------------
|
||||
function lexer :is_keyword (a, ...)
|
||||
if not a or a.tag ~= "Keyword" then return false end
|
||||
local words = {...}
|
||||
if #words == 0 then return a[1] end
|
||||
for _, w in ipairs (words) do
|
||||
if w == a[1] then return w end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- Cause an error if the next token isn't a keyword whose content
|
||||
-- is listed among ... args (which have to be strings).
|
||||
----------------------------------------------------------------------
|
||||
function lexer :check (...)
|
||||
local words = {...}
|
||||
local a = self :next()
|
||||
local function err ()
|
||||
error ("Got " .. tostring (a) ..
|
||||
", expected one of these keywords : '" ..
|
||||
table.concat (words,"', '") .. "'") end
|
||||
if not a or a.tag ~= "Keyword" then err () end
|
||||
if #words == 0 then return a[1] end
|
||||
for _, w in ipairs (words) do
|
||||
if w == a[1] then return w end
|
||||
end
|
||||
err ()
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
function lexer :clone()
|
||||
local alpha_clone, sym_clone = { }, { }
|
||||
for word in pairs(self.alpha) do alpha_clone[word]=true end
|
||||
for letter, list in pairs(self.sym) do sym_clone[letter] = { unpack(list) } end
|
||||
local clone = { alpha=alpha_clone, sym=sym_clone }
|
||||
setmetatable(clone, self)
|
||||
clone.__index = clone
|
||||
return clone
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- Cancel everything left in a lexer, all subsequent attempts at
|
||||
-- `:peek()` or `:next()` will return `Eof`.
|
||||
----------------------------------------------------------------------
|
||||
function lexer :kill()
|
||||
self.i = #self.src+1
|
||||
self.peeked = { }
|
||||
self.attached_comments = { }
|
||||
self.lineinfo_last = self.posfact :get_position (#self.src+1)
|
||||
end
|
||||
|
||||
return M
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,441 +0,0 @@
|
||||
----------------------------------------------------------------------
|
||||
--
|
||||
-- WARNING! You're entering a hackish area, proceed at your own risks!
|
||||
--
|
||||
-- This code results from the borrowing, then ruthless abuse, of
|
||||
-- Yueliang's implementation of Lua 5.0 compiler. I claim
|
||||
-- responsibility for all of the ugly, dirty stuff that you might spot
|
||||
-- in it.
|
||||
--
|
||||
-- Eventually, this code will be rewritten, either in Lua or more
|
||||
-- probably in C. Meanwhile, if you're interested into digging
|
||||
-- metalua's sources, this is not the best part to invest your time
|
||||
-- on.
|
||||
--
|
||||
-- End of warning.
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
|
||||
--[[--------------------------------------------------------------------
|
||||
|
||||
$Id$
|
||||
|
||||
ldump.lua
|
||||
Save bytecodes in Lua
|
||||
This file is part of Yueliang.
|
||||
|
||||
Copyright (c) 2005 Kein-Hong Man <khman@users.sf.net>
|
||||
The COPYRIGHT file describes the conditions
|
||||
under which this software may be distributed.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
[FF] Slightly modified, mainly to produce Lua 5.1 bytecode.
|
||||
|
||||
----------------------------------------------------------------------]]
|
||||
|
||||
--[[--------------------------------------------------------------------
|
||||
-- Notes:
|
||||
-- * LUA_NUMBER (double), byte order (little endian) and some other
|
||||
-- header values hard-coded; see other notes below...
|
||||
-- * One significant difference is that instructions are still in table
|
||||
-- form (with OP/A/B/C/Bx fields) and luaP:Instruction() is needed to
|
||||
-- convert them into 4-char strings
|
||||
-- * Deleted:
|
||||
-- luaU:DumpVector: folded into DumpLines, DumpCode
|
||||
-- * Added:
|
||||
-- luaU:endianness() (from lundump.c)
|
||||
-- luaU:make_setS: create a chunk writer that writes to a string
|
||||
-- luaU:make_setF: create a chunk writer that writes to a file
|
||||
-- (lua.h contains a typedef for a Chunkwriter pointer, and
|
||||
-- a Lua-based implementation exists, writer() in lstrlib.c)
|
||||
-- luaU:from_double(x): encode double value for writing
|
||||
-- luaU:from_int(x): encode integer value for writing
|
||||
-- (error checking is limited for these conversion functions)
|
||||
-- (double conversion does not support denormals or NaNs)
|
||||
-- luaU:ttype(o) (from lobject.h)
|
||||
----------------------------------------------------------------------]]
|
||||
|
||||
module("bytecode", package.seeall)
|
||||
|
||||
format = { }
|
||||
format.header = string.dump(function()end):sub(1, 12)
|
||||
format.little_endian, format.int_size,
|
||||
format.size_t_size, format.instr_size,
|
||||
format.number_size, format.integral = format.header:byte(7, 12)
|
||||
format.little_endian = format.little_endian~=0
|
||||
format.integral = format.integral ~=0
|
||||
|
||||
assert(format.integral or format.number_size==8, "Number format not supported by dumper")
|
||||
assert(format.little_endian, "Big endian architectures not supported by dumper")
|
||||
|
||||
--requires luaP
|
||||
luaU = {}
|
||||
|
||||
-- constants used by dumper
|
||||
luaU.LUA_TNIL = 0
|
||||
luaU.LUA_TBOOLEAN = 1
|
||||
luaU.LUA_TNUMBER = 3 -- (all in lua.h)
|
||||
luaU.LUA_TSTRING = 4
|
||||
luaU.LUA_TNONE = -1
|
||||
|
||||
-- definitions for headers of binary files
|
||||
--luaU.LUA_SIGNATURE = "\27Lua" -- binary files start with "<esc>Lua"
|
||||
--luaU.VERSION = 81 -- 0x50; last format change was in 5.0
|
||||
--luaU.FORMAT_VERSION = 0 -- 0 is official version. yeah I know I'm a liar.
|
||||
|
||||
-- a multiple of PI for testing native format
|
||||
-- multiplying by 1E7 gives non-trivial integer values
|
||||
--luaU.TEST_NUMBER = 3.14159265358979323846E7
|
||||
|
||||
--[[--------------------------------------------------------------------
|
||||
-- Additional functions to handle chunk writing
|
||||
-- * to use make_setS and make_setF, see test_ldump.lua elsewhere
|
||||
----------------------------------------------------------------------]]
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- works like the lobject.h version except that TObject used in these
|
||||
-- scripts only has a 'value' field, no 'tt' field (native types used)
|
||||
------------------------------------------------------------------------
|
||||
function luaU:ttype(o)
|
||||
local tt = type(o.value)
|
||||
if tt == "number" then return self.LUA_TNUMBER
|
||||
elseif tt == "string" then return self.LUA_TSTRING
|
||||
elseif tt == "nil" then return self.LUA_TNIL
|
||||
elseif tt == "boolean" then return self.LUA_TBOOLEAN
|
||||
else
|
||||
return self.LUA_TNONE -- the rest should not appear
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- create a chunk writer that writes to a string
|
||||
-- * returns the writer function and a table containing the string
|
||||
-- * to get the final result, look in buff.data
|
||||
------------------------------------------------------------------------
|
||||
function luaU:make_setS()
|
||||
local buff = {}
|
||||
buff.data = ""
|
||||
local writer =
|
||||
function(s, buff) -- chunk writer
|
||||
if not s then return end
|
||||
buff.data = buff.data..s
|
||||
end
|
||||
return writer, buff
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- create a chunk writer that writes to a file
|
||||
-- * returns the writer function and a table containing the file handle
|
||||
-- * if a nil is passed, then writer should close the open file
|
||||
------------------------------------------------------------------------
|
||||
function luaU:make_setF(filename)
|
||||
local buff = {}
|
||||
buff.h = io.open(filename, "wb")
|
||||
if not buff.h then return nil end
|
||||
local writer =
|
||||
function(s, buff) -- chunk writer
|
||||
if not buff.h then return end
|
||||
if not s then buff.h:close(); return end
|
||||
buff.h:write(s)
|
||||
end
|
||||
return writer, buff
|
||||
end
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
-- converts a IEEE754 double number to an 8-byte little-endian string
|
||||
-- * luaU:from_double() and luaU:from_int() are from ChunkBake project
|
||||
-- * supports +/- Infinity, but not denormals or NaNs
|
||||
-----------------------------------------------------------------------
|
||||
function luaU:from_double(x)
|
||||
local function grab_byte(v)
|
||||
return math.floor(v / 256),
|
||||
string.char(math.mod(math.floor(v), 256))
|
||||
end
|
||||
local sign = 0
|
||||
if x < 0 then sign = 1; x = -x end
|
||||
local mantissa, exponent = math.frexp(x)
|
||||
if x == 0 then -- zero
|
||||
mantissa, exponent = 0, 0
|
||||
elseif x == 1/0 then
|
||||
mantissa, exponent = 0, 2047
|
||||
else
|
||||
mantissa = (mantissa * 2 - 1) * math.ldexp(0.5, 53)
|
||||
exponent = exponent + 1022
|
||||
end
|
||||
local v, byte = "" -- convert to bytes
|
||||
x = mantissa
|
||||
for i = 1,6 do
|
||||
x, byte = grab_byte(x); v = v..byte -- 47:0
|
||||
end
|
||||
x, byte = grab_byte(exponent * 16 + x); v = v..byte -- 55:48
|
||||
x, byte = grab_byte(sign * 128 + x); v = v..byte -- 63:56
|
||||
return v
|
||||
end
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
-- converts a number to a little-endian 32-bit integer string
|
||||
-- * input value assumed to not overflow, can be signed/unsigned
|
||||
-----------------------------------------------------------------------
|
||||
function luaU:from_int(x, size)
|
||||
local v = ""
|
||||
x = math.floor(x)
|
||||
if x >= 0 then
|
||||
for i = 1, size do
|
||||
v = v..string.char(math.mod(x, 256)); x = math.floor(x / 256)
|
||||
end
|
||||
else -- x < 0
|
||||
x = -x
|
||||
local carry = 1
|
||||
for i = 1, size do
|
||||
local c = 255 - math.mod(x, 256) + carry
|
||||
if c == 256 then c = 0; carry = 1 else carry = 0 end
|
||||
v = v..string.char(c); x = math.floor(x / 256)
|
||||
end
|
||||
end
|
||||
return v
|
||||
end
|
||||
|
||||
--[[--------------------------------------------------------------------
|
||||
-- Functions to make a binary chunk
|
||||
-- * many functions have the size parameter removed, since output is
|
||||
-- in the form of a string and some sizes are implicit or hard-coded
|
||||
-- * luaU:DumpVector has been deleted (used in DumpCode & DumpLines)
|
||||
----------------------------------------------------------------------]]
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- dump a block of literal bytes
|
||||
------------------------------------------------------------------------
|
||||
function luaU:DumpLiteral(s, D) self:DumpBlock(s, D) end
|
||||
|
||||
--[[--------------------------------------------------------------------
|
||||
-- struct DumpState:
|
||||
-- L -- lua_State (not used in this script)
|
||||
-- write -- lua_Chunkwriter (chunk writer function)
|
||||
-- data -- void* (chunk writer context or data already written)
|
||||
----------------------------------------------------------------------]]
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- dumps a block of bytes
|
||||
-- * lua_unlock(D.L), lua_lock(D.L) deleted
|
||||
------------------------------------------------------------------------
|
||||
function luaU:DumpBlock(b, D) D.write(b, D.data) end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- dumps a single byte
|
||||
------------------------------------------------------------------------
|
||||
function luaU:DumpByte(y, D)
|
||||
self:DumpBlock(string.char(y), D)
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- dumps a 32-bit signed integer (for int)
|
||||
------------------------------------------------------------------------
|
||||
function luaU:DumpInt(x, D)
|
||||
self:DumpBlock(self:from_int(x, format.int_size), D)
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- dumps a 32-bit unsigned integer (for size_t)
|
||||
------------------------------------------------------------------------
|
||||
function luaU:DumpSize(x, D)
|
||||
self:DumpBlock(self:from_int(x, format.size_t_size), D)
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- dumps a LUA_NUMBER (hard-coded as a double)
|
||||
------------------------------------------------------------------------
|
||||
function luaU:DumpNumber(x, D)
|
||||
if format.integral then
|
||||
self:DumpBlock(self:from_int(x, format.number_size), D)
|
||||
else
|
||||
self:DumpBlock(self:from_double(x), D)
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- dumps a Lua string
|
||||
------------------------------------------------------------------------
|
||||
function luaU:DumpString(s, D)
|
||||
if s == nil then
|
||||
self:DumpSize(0, D)
|
||||
else
|
||||
s = s.."\0" -- include trailing '\0'
|
||||
self:DumpSize(string.len(s), D)
|
||||
self:DumpBlock(s, D)
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- dumps instruction block from function prototype
|
||||
------------------------------------------------------------------------
|
||||
function luaU:DumpCode(f, D)
|
||||
local n = f.sizecode
|
||||
self:DumpInt(n, D)
|
||||
--was DumpVector
|
||||
for i = 0, n - 1 do
|
||||
self:DumpBlock(luaP:Instruction(f.code[i]), D)
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- dumps local variable names from function prototype
|
||||
------------------------------------------------------------------------
|
||||
function luaU:DumpLocals(f, D)
|
||||
local n = f.sizelocvars
|
||||
self:DumpInt(n, D)
|
||||
for i = 0, n - 1 do
|
||||
-- Dirty temporary fix:
|
||||
-- `Stat{ } keeps properly count of the number of local vars,
|
||||
-- but fails to keep score of their debug info (names).
|
||||
-- It therefore might happen that #f.localvars < f.sizelocvars, or
|
||||
-- that a variable's startpc and endpc fields are left unset.
|
||||
-- FIXME: This might not be needed anymore, check the bug report
|
||||
-- by J. Belmonte.
|
||||
local var = f.locvars[i]
|
||||
if not var then break end
|
||||
-- printf("[DUMPLOCALS] dumping local var #%i = %s", i, table.tostring(var))
|
||||
self:DumpString(var.varname, D)
|
||||
self:DumpInt(var.startpc or 0, D)
|
||||
self:DumpInt(var.endpc or 0, D)
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- dumps line information from function prototype
|
||||
------------------------------------------------------------------------
|
||||
function luaU:DumpLines(f, D)
|
||||
local n = f.sizelineinfo
|
||||
self:DumpInt(n, D)
|
||||
--was DumpVector
|
||||
for i = 0, n - 1 do
|
||||
self:DumpInt(f.lineinfo[i], D) -- was DumpBlock
|
||||
--print(i, f.lineinfo[i])
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- dump upvalue names from function prototype
|
||||
------------------------------------------------------------------------
|
||||
function luaU:DumpUpvalues(f, D)
|
||||
local n = f.sizeupvalues
|
||||
self:DumpInt(n, D)
|
||||
for i = 0, n - 1 do
|
||||
self:DumpString(f.upvalues[i], D)
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- dump constant pool from function prototype
|
||||
-- * nvalue(o) and tsvalue(o) macros removed
|
||||
------------------------------------------------------------------------
|
||||
function luaU:DumpConstants(f, D)
|
||||
local n = f.sizek
|
||||
self:DumpInt(n, D)
|
||||
for i = 0, n - 1 do
|
||||
local o = f.k[i] -- TObject
|
||||
local tt = self:ttype(o)
|
||||
assert (tt >= 0)
|
||||
self:DumpByte(tt, D)
|
||||
if tt == self.LUA_TNUMBER then
|
||||
self:DumpNumber(o.value, D)
|
||||
elseif tt == self.LUA_TSTRING then
|
||||
self:DumpString(o.value, D)
|
||||
elseif tt == self.LUA_TBOOLEAN then
|
||||
self:DumpByte (o.value and 1 or 0, D)
|
||||
elseif tt == self.LUA_TNIL then
|
||||
else
|
||||
assert(false) -- cannot happen
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function luaU:DumpProtos (f, D)
|
||||
local n = f.sizep
|
||||
assert (n)
|
||||
self:DumpInt(n, D)
|
||||
for i = 0, n - 1 do
|
||||
self:DumpFunction(f.p[i], f.source, D)
|
||||
end
|
||||
end
|
||||
|
||||
function luaU:DumpDebug(f, D)
|
||||
self:DumpLines(f, D)
|
||||
self:DumpLocals(f, D)
|
||||
self:DumpUpvalues(f, D)
|
||||
end
|
||||
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- dump child function prototypes from function prototype
|
||||
--FF completely reworked for 5.1 format
|
||||
------------------------------------------------------------------------
|
||||
function luaU:DumpFunction(f, p, D)
|
||||
-- print "Dumping function:"
|
||||
-- table.print(f, 60)
|
||||
|
||||
local source = f.source
|
||||
if source == p then source = nil end
|
||||
self:DumpString(source, D)
|
||||
self:DumpInt(f.lineDefined, D)
|
||||
self:DumpInt(f.lastLineDefined or 42, D)
|
||||
self:DumpByte(f.nups, D)
|
||||
self:DumpByte(f.numparams, D)
|
||||
self:DumpByte(f.is_vararg, D)
|
||||
self:DumpByte(f.maxstacksize, D)
|
||||
self:DumpCode(f, D)
|
||||
self:DumpConstants(f, D)
|
||||
self:DumpProtos( f, D)
|
||||
self:DumpDebug(f, D)
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- dump Lua header section (some sizes hard-coded)
|
||||
--FF: updated for version 5.1
|
||||
------------------------------------------------------------------------
|
||||
function luaU:DumpHeader(D)
|
||||
self:DumpLiteral(format.header, D)
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- dump function as precompiled chunk
|
||||
-- * w, data are created from make_setS, make_setF
|
||||
--FF: suppressed extraneous [L] param
|
||||
------------------------------------------------------------------------
|
||||
function luaU:dump (Main, w, data)
|
||||
local D = {} -- DumpState
|
||||
D.write = w
|
||||
D.data = data
|
||||
self:DumpHeader(D)
|
||||
self:DumpFunction(Main, nil, D)
|
||||
-- added: for a chunk writer writing to a file, this final call with
|
||||
-- nil data is to indicate to the writer to close the file
|
||||
D.write(nil, D.data)
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- find byte order (from lundump.c)
|
||||
-- * hard-coded to little-endian
|
||||
------------------------------------------------------------------------
|
||||
function luaU:endianness()
|
||||
return 1
|
||||
end
|
||||
|
||||
-- FIXME: ugly concat-base generation in [make_setS], bufferize properly!
|
||||
function dump_string (proto)
|
||||
local writer, buff = luaU:make_setS()
|
||||
luaU:dump (proto, writer, buff)
|
||||
return buff.data
|
||||
end
|
||||
|
||||
-- FIXME: [make_setS] sucks, perform synchronous file writing
|
||||
-- Now unused
|
||||
function dump_file (proto, filename)
|
||||
local writer, buff = luaU:make_setS()
|
||||
luaU:dump (proto, writer, buff)
|
||||
local file = io.open (filename, "wb")
|
||||
file:write (buff.data)
|
||||
io.close(file)
|
||||
if UNIX_SHARPBANG then os.execute ("chmod a+x "..filename) end
|
||||
end
|
||||
@@ -1,511 +0,0 @@
|
||||
----------------------------------------------------------------------
|
||||
-- Metalua: $Id: mll.lua,v 1.3 2006/11/15 09:07:50 fab13n Exp $
|
||||
--
|
||||
-- Summary: generic Lua-style lexer definition. You need this plus
|
||||
-- some keyword additions to create the complete Lua lexer,
|
||||
-- as is done in mlp_lexer.lua.
|
||||
--
|
||||
-- TODO:
|
||||
--
|
||||
-- * Make it easy to define new flavors of strings. Replacing the
|
||||
-- lexer.patterns.long_string regexp by an extensible list, with
|
||||
-- customizable token tag, would probably be enough. Maybe add:
|
||||
-- + an index of capture for the regexp, that would specify
|
||||
-- which capture holds the content of the string-like token
|
||||
-- + a token tag
|
||||
-- + or a string->string transformer function.
|
||||
--
|
||||
-- * There are some _G.table to prevent a namespace clash which has
|
||||
-- now disappered. remove them.
|
||||
----------------------------------------------------------------------
|
||||
--
|
||||
-- Copyright (c) 2006, Fabien Fleutot <metalua@gmail.com>.
|
||||
--
|
||||
-- This software is released under the MIT Licence, see licence.txt
|
||||
-- for details.
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
|
||||
module ("lexer", package.seeall)
|
||||
|
||||
-- don't load metalua.runtime as it loads metalua.base, which pollutes
|
||||
-- global namespace and overwrites pairs/ipairs -- PK 6/4/2012
|
||||
require 'metalua.table2'
|
||||
|
||||
lexer = { alpha={ }, sym={ } }
|
||||
lexer.__index=lexer
|
||||
|
||||
local debugf = function() end
|
||||
--local debugf=printf
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- Patterns used by [lexer:extract] to decompose the raw string into
|
||||
-- correctly tagged tokens.
|
||||
----------------------------------------------------------------------
|
||||
lexer.patterns = {
|
||||
spaces = "^[ \r\n\t]*()",
|
||||
short_comment = "^%-%-([^\n]*)()\n",
|
||||
final_short_comment = "^%-%-([^\n]*)()$",
|
||||
long_comment = "^%-%-%[(=*)%[\n?(.-)%]%1%]()",
|
||||
long_string = "^%[(=*)%[\n?(.-)%]%1%]()",
|
||||
number_mantissa = { "^%d+%.?%d*()", "^%d*%.%d+()" },
|
||||
number_exponant = "^[eE][%+%-]?%d+()",
|
||||
number_hex = "^0[xX]%x+()",
|
||||
word = "^([%a_][%w_]*)()"
|
||||
}
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- unescape a whole string, applying [unesc_digits] and
|
||||
-- [unesc_letter] as many times as required.
|
||||
----------------------------------------------------------------------
|
||||
local function unescape_string (s)
|
||||
|
||||
-- Turn the digits of an escape sequence into the corresponding
|
||||
-- character, e.g. [unesc_digits("123") == string.char(123)].
|
||||
local function unesc_digits (backslashes, digits)
|
||||
if #backslashes%2==0 then
|
||||
-- Even number of backslashes, they escape each other, not the digits.
|
||||
-- Return them so that unesc_letter() can treaat them
|
||||
return backslashes..digits
|
||||
else
|
||||
-- Remove the odd backslash, which escapes the number sequence.
|
||||
-- The rest will be returned and parsed by unesc_letter()
|
||||
backslashes = backslashes :sub (1,-2)
|
||||
end
|
||||
local k, j, i = digits:reverse():byte(1, 3)
|
||||
local z = _G.string.byte "0"
|
||||
local code = (k or z) + 10*(j or z) + 100*(i or z) - 111*z
|
||||
if code > 255 then
|
||||
error ("Illegal escape sequence '\\"..digits..
|
||||
"' in string: ASCII codes must be in [0..255]")
|
||||
end
|
||||
return backslashes .. string.char (code)
|
||||
end
|
||||
|
||||
-- Take a letter [x], and returns the character represented by the
|
||||
-- sequence ['\\'..x], e.g. [unesc_letter "n" == "\n"].
|
||||
local function unesc_letter(x)
|
||||
local t = {
|
||||
a = "\a", b = "\b", f = "\f",
|
||||
n = "\n", r = "\r", t = "\t", v = "\v",
|
||||
["\\"] = "\\", ["'"] = "'", ['"'] = '"', ["\n"] = "\n" }
|
||||
return t[x] or error([[Unknown escape sequence '\]]..x..[[']])
|
||||
end
|
||||
|
||||
return s
|
||||
:gsub ("(\\+)([0-9][0-9]?[0-9]?)", unesc_digits)
|
||||
:gsub ("\\(%D)",unesc_letter)
|
||||
end
|
||||
|
||||
lexer.extractors = {
|
||||
"skip_whitespaces_and_comments",
|
||||
"extract_short_string", "extract_word", "extract_number",
|
||||
"extract_long_string", "extract_symbol" }
|
||||
|
||||
lexer.token_metatable = {
|
||||
-- __tostring = function(a)
|
||||
-- return string.format ("`%s{'%s'}",a.tag, a[1])
|
||||
-- end
|
||||
}
|
||||
|
||||
lexer.lineinfo_metatable = { }
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- Really extract next token fron the raw string
|
||||
-- (and update the index).
|
||||
-- loc: offset of the position just after spaces and comments
|
||||
-- previous_i: offset in src before extraction began
|
||||
----------------------------------------------------------------------
|
||||
function lexer:extract ()
|
||||
local previous_i = self.i
|
||||
local loc = self.i
|
||||
local eof, token
|
||||
|
||||
-- Put line info, comments and metatable around the tag and content
|
||||
-- provided by extractors, thus returning a complete lexer token.
|
||||
-- first_line: line # at the beginning of token
|
||||
-- first_column_offset: char # of the last '\n' before beginning of token
|
||||
-- i: scans from beginning of prefix spaces/comments to end of token.
|
||||
local function build_token (tag, content)
|
||||
assert (tag and content)
|
||||
local i, first_line, first_column_offset, previous_line_length =
|
||||
previous_i, self.line, self.column_offset, nil
|
||||
|
||||
-- update self.line and first_line. i := indexes of '\n' chars
|
||||
while true do
|
||||
i = self.src :find ("\n", i+1, true)
|
||||
if not i or i>self.i then break end -- no more '\n' until end of token
|
||||
previous_line_length = i - self.column_offset
|
||||
if loc and i <= loc then -- '\n' before beginning of token
|
||||
first_column_offset = i
|
||||
first_line = first_line+1
|
||||
end
|
||||
self.line = self.line+1
|
||||
self.column_offset = i
|
||||
end
|
||||
|
||||
-- lineinfo entries: [1]=line, [2]=column, [3]=char, [4]=filename
|
||||
local fli = { first_line, loc-first_column_offset, loc, self.src_name }
|
||||
local lli = { self.line, self.i-self.column_offset-1, self.i-1, self.src_name }
|
||||
--Pluto barfes when the metatable is set:(
|
||||
setmetatable(fli, lexer.lineinfo_metatable)
|
||||
setmetatable(lli, lexer.lineinfo_metatable)
|
||||
local a = { tag = tag, lineinfo = { first=fli, last=lli }, content }
|
||||
if lli[2]==-1 then lli[1], lli[2] = lli[1]-1, previous_line_length-1 end
|
||||
if #self.attached_comments > 0 then
|
||||
a.lineinfo.comments = self.attached_comments
|
||||
fli.comments = self.attached_comments
|
||||
if self.lineinfo_last then
|
||||
self.lineinfo_last.comments = self.attached_comments
|
||||
end
|
||||
end
|
||||
self.attached_comments = { }
|
||||
return setmetatable (a, self.token_metatable)
|
||||
end --</function build_token>
|
||||
|
||||
for ext_idx, extractor in ipairs(self.extractors) do
|
||||
-- printf("method = %s", method)
|
||||
local tag, content = self [extractor] (self)
|
||||
-- [loc] is placed just after the leading whitespaces and comments;
|
||||
-- for this to work, the whitespace extractor *must be* at index 1.
|
||||
if ext_idx==1 then loc = self.i end
|
||||
|
||||
if tag then
|
||||
--printf("`%s{ %q }\t%i", tag, content, loc);
|
||||
return build_token (tag, content)
|
||||
end
|
||||
end
|
||||
|
||||
error "None of the lexer extractors returned anything!"
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- skip whites and comments
|
||||
-- FIXME: doesn't take into account:
|
||||
-- - unterminated long comments
|
||||
-- - short comments at last line without a final \n
|
||||
----------------------------------------------------------------------
|
||||
function lexer:skip_whitespaces_and_comments()
|
||||
local table_insert = _G.table.insert
|
||||
repeat -- loop as long as a space or comment chunk is found
|
||||
local _, j
|
||||
local again = false
|
||||
local last_comment_content = nil
|
||||
-- skip spaces
|
||||
self.i = self.src:match (self.patterns.spaces, self.i)
|
||||
-- skip a long comment if any
|
||||
_, last_comment_content, j =
|
||||
self.src :match (self.patterns.long_comment, self.i)
|
||||
if j then
|
||||
table_insert(self.attached_comments,
|
||||
{last_comment_content, self.i, j, "long"})
|
||||
self.i=j; again=true
|
||||
end
|
||||
-- skip a short comment if any
|
||||
last_comment_content, j = self.src:match (self.patterns.short_comment, self.i)
|
||||
if j then
|
||||
table_insert(self.attached_comments,
|
||||
{last_comment_content, self.i, j, "short"})
|
||||
self.i=j; again=true
|
||||
end
|
||||
if self.i>#self.src then return "Eof", "eof" end
|
||||
until not again
|
||||
|
||||
if self.src:match (self.patterns.final_short_comment, self.i) then
|
||||
return "Eof", "eof" end
|
||||
--assert (not self.src:match(self.patterns.short_comment, self.i))
|
||||
--assert (not self.src:match(self.patterns.long_comment, self.i))
|
||||
-- --assert (not self.src:match(self.patterns.spaces, self.i))
|
||||
return
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- extract a '...' or "..." short string
|
||||
----------------------------------------------------------------------
|
||||
function lexer:extract_short_string()
|
||||
-- [k] is the first unread char, [self.i] points to [k] in [self.src]
|
||||
local j, k = self.i, self.src :sub (self.i,self.i)
|
||||
if k~="'" and k~='"' then return end
|
||||
local i = self.i + 1
|
||||
local j = i
|
||||
while true do
|
||||
-- k = opening char: either simple-quote or double-quote
|
||||
-- i = index of beginning-of-string
|
||||
-- x = next "interesting" character
|
||||
-- j = position after interesting char
|
||||
-- y = char just after x
|
||||
local x, y
|
||||
x, j, y = self.src :match ("([\\\r\n"..k.."])()(.?)", j)
|
||||
if x == '\\' then j=j+1 -- don't parse escaped char
|
||||
elseif x == k then break -- unescaped end of string
|
||||
else -- eof or '\r' or '\n' reached before end of string
|
||||
assert (not x or x=="\r" or x=="\n")
|
||||
error "Unterminated string"
|
||||
end
|
||||
end
|
||||
self.i = j
|
||||
|
||||
return "String", unescape_string (self.src:sub (i,j-2))
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
function lexer:extract_word()
|
||||
-- Id / keyword
|
||||
local word, j = self.src:match (self.patterns.word, self.i)
|
||||
if word then
|
||||
self.i = j
|
||||
if self.alpha [word] then return "Keyword", word
|
||||
else return "Id", word end
|
||||
end
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
function lexer:extract_number()
|
||||
-- Number
|
||||
local j = self.src:match(self.patterns.number_hex, self.i)
|
||||
if not j then
|
||||
j = self.src:match (self.patterns.number_mantissa[1], self.i) or
|
||||
self.src:match (self.patterns.number_mantissa[2], self.i)
|
||||
if j then
|
||||
j = self.src:match (self.patterns.number_exponant, j) or j;
|
||||
end
|
||||
end
|
||||
if not j then return end
|
||||
-- Number found, interpret with tonumber() and return it
|
||||
local n = tonumber (self.src:sub (self.i, j-1))
|
||||
self.i = j
|
||||
return "Number", n
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
function lexer:extract_long_string()
|
||||
-- Long string
|
||||
local _, content, j = self.src:match (self.patterns.long_string, self.i)
|
||||
if j then self.i = j; return "String", content end
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
function lexer:extract_symbol()
|
||||
-- compound symbol
|
||||
local k = self.src:sub (self.i,self.i)
|
||||
local symk = self.sym [k]
|
||||
if not symk then
|
||||
self.i = self.i + 1
|
||||
return "Keyword", k
|
||||
end
|
||||
for _, sym in pairs (symk) do
|
||||
if sym == self.src:sub (self.i, self.i + #sym - 1) then
|
||||
self.i = self.i + #sym;
|
||||
return "Keyword", sym
|
||||
end
|
||||
end
|
||||
-- single char symbol
|
||||
self.i = self.i+1
|
||||
return "Keyword", k
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- Add a keyword to the list of keywords recognized by the lexer.
|
||||
----------------------------------------------------------------------
|
||||
function lexer:add (w, ...)
|
||||
assert(not ..., "lexer:add() takes only one arg, although possibly a table")
|
||||
if type (w) == "table" then
|
||||
for _, x in ipairs (w) do self:add (x) end
|
||||
else
|
||||
if w:match (self.patterns.word .. "$") then self.alpha [w] = true
|
||||
elseif w:match "^%p%p+$" then
|
||||
local k = w:sub(1,1)
|
||||
local list = self.sym [k]
|
||||
if not list then list = { }; self.sym [k] = list end
|
||||
_G.table.insert (list, w)
|
||||
elseif w:match "^%p$" then return
|
||||
else error "Invalid keyword" end
|
||||
end
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- Return the [n]th next token, without consumming it.
|
||||
-- [n] defaults to 1. If it goes pass the end of the stream, an EOF
|
||||
-- token is returned.
|
||||
----------------------------------------------------------------------
|
||||
function lexer:peek (n)
|
||||
if not n then n=1 end
|
||||
if n > #self.peeked then
|
||||
for i = #self.peeked+1, n do
|
||||
self.peeked [i] = self:extract()
|
||||
end
|
||||
end
|
||||
return self.peeked [n]
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- Return the [n]th next token, removing it as well as the 0..n-1
|
||||
-- previous tokens. [n] defaults to 1. If it goes pass the end of the
|
||||
-- stream, an EOF token is returned.
|
||||
----------------------------------------------------------------------
|
||||
function lexer:next (n)
|
||||
n = n or 1
|
||||
self:peek (n)
|
||||
local a
|
||||
for i=1,n do
|
||||
a = _G.table.remove (self.peeked, 1)
|
||||
if a then
|
||||
--debugf ("lexer:next() ==> %s %s",
|
||||
-- table.tostring(a), tostring(a))
|
||||
end
|
||||
self.lastline = a.lineinfo.last[1]
|
||||
end
|
||||
self.lineinfo_last = a.lineinfo.last
|
||||
return a or eof_token
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- Returns an object which saves the stream's current state.
|
||||
----------------------------------------------------------------------
|
||||
-- FIXME there are more fields than that to save
|
||||
function lexer:save () return { self.i; _G.table.cat(self.peeked) } end
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- Restore the stream's state, as saved by method [save].
|
||||
----------------------------------------------------------------------
|
||||
-- FIXME there are more fields than that to restore
|
||||
function lexer:restore (s) self.i=s[1]; self.peeked=s[2] end
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- Resynchronize: cancel any token in self.peeked, by emptying the
|
||||
-- list and resetting the indexes
|
||||
----------------------------------------------------------------------
|
||||
function lexer:sync()
|
||||
local p1 = self.peeked[1]
|
||||
if p1 then
|
||||
li = p1.lineinfo.first
|
||||
self.line, self.i = li[1], li[3]
|
||||
self.column_offset = self.i - li[2]
|
||||
self.peeked = { }
|
||||
self.attached_comments = p1.lineinfo.first.comments or { }
|
||||
end
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- Take the source and offset of an old lexer.
|
||||
----------------------------------------------------------------------
|
||||
function lexer:takeover(old)
|
||||
self:sync()
|
||||
self.line, self.column_offset, self.i, self.src, self.attached_comments =
|
||||
old.line, old.column_offset, old.i, old.src, old.attached_comments
|
||||
return self
|
||||
end
|
||||
|
||||
-- function lexer:lineinfo()
|
||||
-- if self.peeked[1] then return self.peeked[1].lineinfo.first
|
||||
-- else return { self.line, self.i-self.column_offset, self.i } end
|
||||
-- end
|
||||
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- Return the current position in the sources. This position is between
|
||||
-- two tokens, and can be within a space / comment area, and therefore
|
||||
-- have a non-null width. :lineinfo_left() returns the beginning of the
|
||||
-- separation area, :lineinfo_right() returns the end of that area.
|
||||
--
|
||||
-- ____ last consummed token ____ first unconsummed token
|
||||
-- / /
|
||||
-- XXXXX <spaces and comments> YYYYY
|
||||
-- \____ \____
|
||||
-- :lineinfo_left() :lineinfo_right()
|
||||
----------------------------------------------------------------------
|
||||
function lexer:lineinfo_right()
|
||||
return self:peek(1).lineinfo.first
|
||||
end
|
||||
|
||||
function lexer:lineinfo_left()
|
||||
return self.lineinfo_last
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- Create a new lexstream.
|
||||
----------------------------------------------------------------------
|
||||
function lexer:newstream (src_or_stream, name)
|
||||
name = name or "?"
|
||||
if type(src_or_stream)=='table' then -- it's a stream
|
||||
return setmetatable ({ }, self) :takeover (src_or_stream)
|
||||
elseif type(src_or_stream)=='string' then -- it's a source string
|
||||
local src = src_or_stream
|
||||
local stream = {
|
||||
src_name = name; -- Name of the file
|
||||
src = src; -- The source, as a single string
|
||||
peeked = { }; -- Already peeked, but not discarded yet, tokens
|
||||
i = 1; -- Character offset in src
|
||||
line = 1; -- Current line number
|
||||
column_offset = 0; -- distance from beginning of file to last '\n'
|
||||
attached_comments = { },-- comments accumulator
|
||||
lineinfo_last = { 1, 1, 1, name }
|
||||
}
|
||||
setmetatable (stream, self)
|
||||
|
||||
-- skip initial sharp-bang for unix scripts
|
||||
-- FIXME: redundant with mlp.chunk()
|
||||
if src and src :match "^#" then stream.i = src :find "\n" + 1 end
|
||||
return stream
|
||||
else
|
||||
assert(false, ":newstream() takes a source string or a stream, not a "..
|
||||
type(src_or_stream))
|
||||
end
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- if there's no ... args, return the token a (whose truth value is
|
||||
-- true) if it's a `Keyword{ }, or nil. If there are ... args, they
|
||||
-- have to be strings. if the token a is a keyword, and it's content
|
||||
-- is one of the ... args, then returns it (it's truth value is
|
||||
-- true). If no a keyword or not in ..., return nil.
|
||||
----------------------------------------------------------------------
|
||||
function lexer:is_keyword (a, ...)
|
||||
if not a or a.tag ~= "Keyword" then return false end
|
||||
local words = {...}
|
||||
if #words == 0 then return a[1] end
|
||||
for _, w in ipairs (words) do
|
||||
if w == a[1] then return w end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- Cause an error if the next token isn't a keyword whose content
|
||||
-- is listed among ... args (which have to be strings).
|
||||
----------------------------------------------------------------------
|
||||
function lexer:check (...)
|
||||
local words = {...}
|
||||
local a = self:next()
|
||||
local function err ()
|
||||
error ("Got " .. tostring (a) ..
|
||||
", expected one of these keywords : '" ..
|
||||
_G.table.concat (words,"', '") .. "'") end
|
||||
|
||||
if not a or a.tag ~= "Keyword" then err () end
|
||||
if #words == 0 then return a[1] end
|
||||
for _, w in ipairs (words) do
|
||||
if w == a[1] then return w end
|
||||
end
|
||||
err ()
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
function lexer:clone()
|
||||
local clone = {
|
||||
alpha = table.deep_copy(self.alpha),
|
||||
sym = table.deep_copy(self.sym) }
|
||||
setmetatable(clone, self)
|
||||
clone.__index = clone
|
||||
return clone
|
||||
end
|
||||
@@ -1,440 +0,0 @@
|
||||
----------------------------------------------------------------------
|
||||
--
|
||||
-- WARNING! You're entering a hackish area, proceed at your own risks!
|
||||
--
|
||||
-- This code results from the borrowing, then ruthless abuse, of
|
||||
-- Yueliang's implementation of Lua 5.0 compiler. I claim
|
||||
-- responsibility for all of the ugly, dirty stuff that you might spot
|
||||
-- in it.
|
||||
--
|
||||
-- Eventually, this code will be rewritten, either in Lua or more
|
||||
-- probably in C. Meanwhile, if you're interested into digging
|
||||
-- metalua's sources, this is not the best part to invest your time
|
||||
-- on.
|
||||
--
|
||||
-- End of warning.
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
|
||||
--[[--------------------------------------------------------------------
|
||||
|
||||
$Id$
|
||||
|
||||
lopcodes.lua
|
||||
Lua 5 virtual machine opcodes in Lua
|
||||
This file is part of Yueliang.
|
||||
|
||||
Copyright (c) 2005 Kein-Hong Man <khman@users.sf.net>
|
||||
The COPYRIGHT file describes the conditions
|
||||
under which this software may be distributed.
|
||||
|
||||
See the ChangeLog for more information.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
[FF] Slightly modified, mainly to produce Lua 5.1 bytecode.
|
||||
|
||||
----------------------------------------------------------------------]]
|
||||
|
||||
--[[--------------------------------------------------------------------
|
||||
-- Notes:
|
||||
-- * an Instruction is a table with OP, A, B, C, Bx elements; this
|
||||
-- should allow instruction handling to work with doubles and ints
|
||||
-- * Added:
|
||||
-- luaP:Instruction(i): convert field elements to a 4-char string
|
||||
-- luaP:DecodeInst(x): convert 4-char string into field elements
|
||||
-- * WARNING luaP:Instruction outputs instructions encoded in little-
|
||||
-- endian form and field size and positions are hard-coded
|
||||
----------------------------------------------------------------------]]
|
||||
|
||||
module("bytecode", package.seeall)
|
||||
|
||||
local function debugf() end
|
||||
|
||||
luaP = { }
|
||||
|
||||
--[[
|
||||
===========================================================================
|
||||
We assume that instructions are unsigned numbers.
|
||||
All instructions have an opcode in the first 6 bits.
|
||||
Instructions can have the following fields:
|
||||
'A' : 8 bits
|
||||
'B' : 9 bits
|
||||
'C' : 9 bits
|
||||
'Bx' : 18 bits ('B' and 'C' together)
|
||||
'sBx' : signed Bx
|
||||
|
||||
A signed argument is represented in excess K; that is, the number
|
||||
value is the unsigned value minus K. K is exactly the maximum value
|
||||
for that argument (so that -max is represented by 0, and +max is
|
||||
represented by 2*max), which is half the maximum for the corresponding
|
||||
unsigned argument.
|
||||
===========================================================================
|
||||
--]]
|
||||
|
||||
luaP.OpMode = {"iABC", "iABx", "iAsBx"} -- basic instruction format
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- size and position of opcode arguments.
|
||||
-- * WARNING size and position is hard-coded elsewhere in this script
|
||||
------------------------------------------------------------------------
|
||||
luaP.SIZE_C = 9
|
||||
luaP.SIZE_B = 9
|
||||
luaP.SIZE_Bx = luaP.SIZE_C + luaP.SIZE_B
|
||||
luaP.SIZE_A = 8
|
||||
|
||||
luaP.SIZE_OP = 6
|
||||
|
||||
luaP.POS_C = luaP.SIZE_OP
|
||||
luaP.POS_B = luaP.POS_C + luaP.SIZE_C
|
||||
luaP.POS_Bx = luaP.POS_C
|
||||
luaP.POS_A = luaP.POS_B + luaP.SIZE_B
|
||||
|
||||
--FF from 5.1
|
||||
luaP.BITRK = 2^(luaP.SIZE_B - 1)
|
||||
function luaP:ISK(x) return x >= self.BITRK end
|
||||
luaP.MAXINDEXRK = luaP.BITRK - 1
|
||||
function luaP:RKASK(x)
|
||||
if x < self.BITRK then return x+self.BITRK else return x end
|
||||
end
|
||||
|
||||
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- limits for opcode arguments.
|
||||
-- we use (signed) int to manipulate most arguments,
|
||||
-- so they must fit in BITS_INT-1 bits (-1 for sign)
|
||||
------------------------------------------------------------------------
|
||||
-- removed "#if SIZE_Bx < BITS_INT-1" test, assume this script is
|
||||
-- running on a Lua VM with double or int as LUA_NUMBER
|
||||
|
||||
luaP.MAXARG_Bx = math.ldexp(1, luaP.SIZE_Bx) - 1
|
||||
luaP.MAXARG_sBx = math.floor(luaP.MAXARG_Bx / 2) -- 'sBx' is signed
|
||||
|
||||
luaP.MAXARG_A = math.ldexp(1, luaP.SIZE_A) - 1
|
||||
luaP.MAXARG_B = math.ldexp(1, luaP.SIZE_B) - 1
|
||||
luaP.MAXARG_C = math.ldexp(1, luaP.SIZE_C) - 1
|
||||
|
||||
-- creates a mask with 'n' 1 bits at position 'p'
|
||||
-- MASK1(n,p) deleted
|
||||
-- creates a mask with 'n' 0 bits at position 'p'
|
||||
-- MASK0(n,p) deleted
|
||||
|
||||
--[[--------------------------------------------------------------------
|
||||
Visual representation for reference:
|
||||
|
||||
31 | | | 0 bit position
|
||||
+-----+-----+-----+----------+
|
||||
| B | C | A | Opcode | iABC format
|
||||
+-----+-----+-----+----------+
|
||||
- 9 - 9 - 8 - 6 - field sizes
|
||||
+-----+-----+-----+----------+
|
||||
| [s]Bx | A | Opcode | iABx | iAsBx format
|
||||
+-----+-----+-----+----------+
|
||||
----------------------------------------------------------------------]]
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- the following macros help to manipulate instructions
|
||||
-- * changed to a table object representation, very clean compared to
|
||||
-- the [nightmare] alternatives of using a number or a string
|
||||
------------------------------------------------------------------------
|
||||
|
||||
-- these accept or return opcodes in the form of string names
|
||||
function luaP:GET_OPCODE(i) return self.ROpCode[i.OP] end
|
||||
function luaP:SET_OPCODE(i, o) i.OP = self.OpCode[o] end
|
||||
|
||||
function luaP:GETARG_A(i) return i.A end
|
||||
function luaP:SETARG_A(i, u) i.A = u end
|
||||
|
||||
function luaP:GETARG_B(i) return i.B end
|
||||
function luaP:SETARG_B(i, b) i.B = b end
|
||||
|
||||
function luaP:GETARG_C(i) return i.C end
|
||||
function luaP:SETARG_C(i, b) i.C = b end
|
||||
|
||||
function luaP:GETARG_Bx(i) return i.Bx end
|
||||
function luaP:SETARG_Bx(i, b) i.Bx = b end
|
||||
|
||||
function luaP:GETARG_sBx(i) return i.Bx - self.MAXARG_sBx end
|
||||
function luaP:SETARG_sBx(i, b) i.Bx = b + self.MAXARG_sBx end
|
||||
|
||||
function luaP:CREATE_ABC(o,a,b,c)
|
||||
return {OP = self.OpCode[o], A = a, B = b, C = c}
|
||||
end
|
||||
|
||||
function luaP:CREATE_ABx(o,a,bc)
|
||||
return {OP = self.OpCode[o], A = a, Bx = bc}
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- Bit shuffling stuffs
|
||||
------------------------------------------------------------------------
|
||||
|
||||
if false and pcall (require, 'bit') then
|
||||
------------------------------------------------------------------------
|
||||
-- Return a 4-char string little-endian encoded form of an instruction
|
||||
------------------------------------------------------------------------
|
||||
function luaP:Instruction(i)
|
||||
--FIXME
|
||||
end
|
||||
else
|
||||
------------------------------------------------------------------------
|
||||
-- Version without bit manipulation library.
|
||||
------------------------------------------------------------------------
|
||||
local p2 = {1,2,4,8,16,32,64,128,256, 512, 1024, 2048, 4096}
|
||||
-- keeps [n] bits from [x]
|
||||
local function keep (x, n) return x % p2[n+1] end
|
||||
-- shifts bits of [x] [n] places to the right
|
||||
local function srb (x,n) return math.floor (x / p2[n+1]) end
|
||||
-- shifts bits of [x] [n] places to the left
|
||||
local function slb (x,n) return x * p2[n+1] end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- Return a 4-char string little-endian encoded form of an instruction
|
||||
------------------------------------------------------------------------
|
||||
function luaP:Instruction(i)
|
||||
-- printf("Instr->string: %s %s", self.opnames[i.OP], table.tostring(i))
|
||||
local c0, c1, c2, c3
|
||||
-- change to OP/A/B/C format if needed
|
||||
if i.Bx then i.C = keep (i.Bx, 9); i.B = srb (i.Bx, 9) end
|
||||
-- c0 = 6B from opcode + 2LSB from A (flushed to MSB)
|
||||
c0 = i.OP + slb (keep (i.A, 2), 6)
|
||||
-- c1 = 6MSB from A + 2LSB from C (flushed to MSB)
|
||||
c1 = srb (i.A, 2) + slb (keep (i.C, 2), 6)
|
||||
-- c2 = 7MSB from C + 1LSB from B (flushed to MSB)
|
||||
c2 = srb (i.C, 2) + slb (keep (i.B, 1), 7)
|
||||
-- c3 = 8MSB from B
|
||||
c3 = srb (i.B, 1)
|
||||
--printf ("Instruction: %s %s", self.opnames[i.OP], tostringv (i))
|
||||
--printf ("Bin encoding: %x %x %x %x", c0, c1, c2, c3)
|
||||
return string.char(c0, c1, c2, c3)
|
||||
end
|
||||
end
|
||||
------------------------------------------------------------------------
|
||||
-- decodes a 4-char little-endian string into an instruction struct
|
||||
------------------------------------------------------------------------
|
||||
function luaP:DecodeInst(x)
|
||||
error "Not implemented"
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- invalid register that fits in 8 bits
|
||||
------------------------------------------------------------------------
|
||||
luaP.NO_REG = luaP.MAXARG_A
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- R(x) - register
|
||||
-- Kst(x) - constant (in constant table)
|
||||
-- RK(x) == if x < MAXSTACK then R(x) else Kst(x-MAXSTACK)
|
||||
------------------------------------------------------------------------
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- grep "ORDER OP" if you change these enums
|
||||
------------------------------------------------------------------------
|
||||
|
||||
--[[--------------------------------------------------------------------
|
||||
Lua virtual machine opcodes (enum OpCode):
|
||||
------------------------------------------------------------------------
|
||||
name args description
|
||||
------------------------------------------------------------------------
|
||||
OP_MOVE A B R(A) := R(B)
|
||||
OP_LOADK A Bx R(A) := Kst(Bx)
|
||||
OP_LOADBOOL A B C R(A) := (Bool)B; if (C) PC++
|
||||
OP_LOADNIL A B R(A) := ... := R(B) := nil
|
||||
OP_GETUPVAL A B R(A) := UpValue[B]
|
||||
OP_GETGLOBAL A Bx R(A) := Gbl[Kst(Bx)]
|
||||
OP_GETTABLE A B C R(A) := R(B)[RK(C)]
|
||||
OP_SETGLOBAL A Bx Gbl[Kst(Bx)] := R(A)
|
||||
OP_SETUPVAL A B UpValue[B] := R(A)
|
||||
OP_SETTABLE A B C R(A)[RK(B)] := RK(C)
|
||||
OP_NEWTABLE A B C R(A) := {} (size = B,C)
|
||||
OP_SELF A B C R(A+1) := R(B); R(A) := R(B)[RK(C)]
|
||||
OP_ADD A B C R(A) := RK(B) + RK(C)
|
||||
OP_SUB A B C R(A) := RK(B) - RK(C)
|
||||
OP_MUL A B C R(A) := RK(B) * RK(C)
|
||||
OP_DIV A B C R(A) := RK(B) / RK(C)
|
||||
OP_POW A B C R(A) := RK(B) ^ RK(C)
|
||||
OP_UNM A B R(A) := -R(B)
|
||||
OP_NOT A B R(A) := not R(B)
|
||||
OP_CONCAT A B C R(A) := R(B).. ... ..R(C)
|
||||
OP_JMP sBx PC += sBx
|
||||
OP_EQ A B C if ((RK(B) == RK(C)) ~= A) then pc++
|
||||
OP_LT A B C if ((RK(B) < RK(C)) ~= A) then pc++
|
||||
OP_LE A B C if ((RK(B) <= RK(C)) ~= A) then pc++
|
||||
OP_TEST A B C if (R(B) <=> C) then R(A) := R(B) else pc++
|
||||
OP_CALL A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1))
|
||||
OP_TAILCALL A B C return R(A)(R(A+1), ... ,R(A+B-1))
|
||||
OP_RETURN A B return R(A), ... ,R(A+B-2) (see note)
|
||||
OP_FORLOOP A sBx R(A)+=R(A+2); if R(A) <?= R(A+1) then PC+= sBx
|
||||
OP_TFORLOOP A C R(A+2), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2));
|
||||
if R(A+2) ~= nil then pc++
|
||||
OP_TFORPREP A sBx if type(R(A)) == table then R(A+1):=R(A), R(A):=next;
|
||||
PC += sBx
|
||||
OP_SETLIST A Bx R(A)[Bx-Bx%FPF+i] := R(A+i), 1 <= i <= Bx%FPF+1
|
||||
OP_SETLISTO A Bx (see note)
|
||||
OP_CLOSE A close all variables in the stack up to (>=) R(A)
|
||||
OP_CLOSURE A Bx R(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n))
|
||||
----------------------------------------------------------------------]]
|
||||
|
||||
luaP.opnames = {} -- opcode names
|
||||
luaP.OpCode = {} -- lookup name -> number
|
||||
luaP.ROpCode = {} -- lookup number -> name
|
||||
|
||||
local i = 0
|
||||
for v in string.gmatch([[
|
||||
MOVE -- 0
|
||||
LOADK
|
||||
LOADBOOL
|
||||
LOADNIL
|
||||
GETUPVAL
|
||||
GETGLOBAL -- 5
|
||||
GETTABLE
|
||||
SETGLOBAL
|
||||
SETUPVAL
|
||||
SETTABLE
|
||||
NEWTABLE -- 10
|
||||
SELF
|
||||
ADD
|
||||
SUB
|
||||
MUL
|
||||
DIV -- 15
|
||||
MOD
|
||||
POW
|
||||
UNM
|
||||
NOT
|
||||
LEN -- 20
|
||||
CONCAT
|
||||
JMP
|
||||
EQ
|
||||
LT
|
||||
LE -- 25
|
||||
TEST
|
||||
TESTSET
|
||||
CALL
|
||||
TAILCALL
|
||||
RETURN -- 30
|
||||
FORLOOP
|
||||
FORPREP
|
||||
TFORLOOP
|
||||
SETLIST
|
||||
CLOSE -- 35
|
||||
CLOSURE
|
||||
VARARG
|
||||
]], "[%a]+") do
|
||||
local n = "OP_"..v
|
||||
luaP.opnames[i] = v
|
||||
luaP.OpCode[n] = i
|
||||
luaP.ROpCode[i] = n
|
||||
i = i + 1
|
||||
end
|
||||
luaP.NUM_OPCODES = i
|
||||
|
||||
--[[
|
||||
===========================================================================
|
||||
Notes:
|
||||
(1) In OP_CALL, if (B == 0) then B = top. C is the number of returns - 1,
|
||||
and can be 0: OP_CALL then sets 'top' to last_result+1, so
|
||||
next open instruction (OP_CALL, OP_RETURN, OP_SETLIST) may use 'top'.
|
||||
|
||||
(2) In OP_RETURN, if (B == 0) then return up to 'top'
|
||||
|
||||
(3) For comparisons, B specifies what conditions the test should accept.
|
||||
|
||||
(4) All 'skips' (pc++) assume that next instruction is a jump
|
||||
|
||||
(5) OP_SETLISTO is used when the last item in a table constructor is a
|
||||
function, so the number of elements set is up to top of stack
|
||||
===========================================================================
|
||||
--]]
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- masks for instruction properties
|
||||
------------------------------------------------------------------------
|
||||
-- was enum OpModeMask:
|
||||
luaP.OpModeBreg = 2 -- B is a register
|
||||
luaP.OpModeBrk = 3 -- B is a register/constant
|
||||
luaP.OpModeCrk = 4 -- C is a register/constant
|
||||
luaP.OpModesetA = 5 -- instruction set register A
|
||||
luaP.OpModeK = 6 -- Bx is a constant
|
||||
luaP.OpModeT = 1 -- operator is a test
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- get opcode mode, e.g. "iABC"
|
||||
------------------------------------------------------------------------
|
||||
function luaP:getOpMode(m)
|
||||
--printv(m)
|
||||
--printv(self.OpCode[m])
|
||||
--printv(self.opmodes [self.OpCode[m]+1])
|
||||
return self.OpMode[tonumber(string.sub(self.opmodes[self.OpCode[m] + 1], 7, 7))]
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- test an instruction property flag
|
||||
-- * b is a string, e.g. "OpModeBreg"
|
||||
------------------------------------------------------------------------
|
||||
function luaP:testOpMode(m, b)
|
||||
return (string.sub(self.opmodes[self.OpCode[m] + 1], self[b], self[b]) == "1")
|
||||
end
|
||||
|
||||
-- number of list items to accumulate before a SETLIST instruction
|
||||
-- (must be a power of 2)
|
||||
-- * used in lparser, lvm, ldebug, ltests
|
||||
luaP.LFIELDS_PER_FLUSH = 50 --FF updated to match 5.1
|
||||
|
||||
-- luaP_opnames[] is set above, as the luaP.opnames table
|
||||
-- opmode(t,b,bk,ck,sa,k,m) deleted
|
||||
|
||||
--[[--------------------------------------------------------------------
|
||||
Legend for luaP:opmodes:
|
||||
1 T -> T (is a test?)
|
||||
2 B -> B is a register
|
||||
3 b -> B is an RK register/constant combination
|
||||
4 C -> C is an RK register/constant combination
|
||||
5 A -> register A is set by the opcode
|
||||
6 K -> Bx is a constant
|
||||
7 m -> 1 if iABC layout,
|
||||
2 if iABx layout,
|
||||
3 if iAsBx layout
|
||||
----------------------------------------------------------------------]]
|
||||
|
||||
luaP.opmodes = {
|
||||
-- TBbCAKm opcode
|
||||
"0100101", -- OP_MOVE 0
|
||||
"0000112", -- OP_LOADK
|
||||
"0000101", -- OP_LOADBOOL
|
||||
"0100101", -- OP_LOADNIL
|
||||
"0000101", -- OP_GETUPVAL
|
||||
"0000112", -- OP_GETGLOBAL 5
|
||||
"0101101", -- OP_GETTABLE
|
||||
"0000012", -- OP_SETGLOBAL
|
||||
"0000001", -- OP_SETUPVAL
|
||||
"0011001", -- OP_SETTABLE
|
||||
"0000101", -- OP_NEWTABLE 10
|
||||
"0101101", -- OP_SELF
|
||||
"0011101", -- OP_ADD
|
||||
"0011101", -- OP_SUB
|
||||
"0011101", -- OP_MUL
|
||||
"0011101", -- OP_DIV 15
|
||||
"0011101", -- OP_MOD
|
||||
"0011101", -- OP_POW
|
||||
"0100101", -- OP_UNM
|
||||
"0100101", -- OP_NOT
|
||||
"0100101", -- OP_LEN 20
|
||||
"0101101", -- OP_CONCAT
|
||||
"0000003", -- OP_JMP
|
||||
"1011001", -- OP_EQ
|
||||
"1011001", -- OP_LT
|
||||
"1011001", -- OP_LE 25
|
||||
"1000101", -- OP_TEST
|
||||
"1100101", -- OP_TESTSET
|
||||
"0000001", -- OP_CALL
|
||||
"0000001", -- OP_TAILCALL
|
||||
"0000001", -- OP_RETURN 30
|
||||
"0000003", -- OP_FORLOOP
|
||||
"0000103", -- OP_FORPREP
|
||||
"1000101", -- OP_TFORLOOP
|
||||
"0000001", -- OP_SETLIST
|
||||
"0000001", -- OP_CLOSE 35
|
||||
"0000102", -- OP_CLOSURE
|
||||
"0000101" -- OP_VARARG
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
-- construct proper path to load metalua modules to build
|
||||
-- an abstract syntax tree (AST)
|
||||
local file = debug.getinfo(1, "S").source
|
||||
if string.find(file, "@") == 1 then file = string.sub(file, 2) end
|
||||
package.path = string.gsub(file, "metalua%.lua$", "?.lua") .. ';' .. package.path
|
||||
|
||||
-- these modules are sufficient to build an AST from a source file/string
|
||||
require "lexer"
|
||||
require "gg"
|
||||
require "mlp_lexer"
|
||||
require "mlp_misc"
|
||||
require "mlp_table"
|
||||
require "mlp_meta"
|
||||
require "mlp_expr"
|
||||
require "mlp_stat"
|
||||
|
||||
-- these modules are needed to convert an AST into bytecode to execute
|
||||
require "lcode"
|
||||
require "ldump"
|
||||
require "lopcodes"
|
||||
require "compile"
|
||||
|
||||
-- this is the compiler module that builds bytecode from an AST
|
||||
local mlc = { }
|
||||
|
||||
function mlc.function_of_ast (ast)
|
||||
local proto = bytecode.metalua_compile(ast)
|
||||
local dump = bytecode.dump_string(proto)
|
||||
local func = string.undump(dump)
|
||||
return func
|
||||
end
|
||||
|
||||
function mlc.ast_of_luastring (src, file)
|
||||
local lx = mlp.lexer:newstream(src, file or "(string)")
|
||||
local ast = mlp.chunk(lx)
|
||||
return ast
|
||||
end
|
||||
|
||||
function mlc.function_of_luastring (src, file)
|
||||
local ast = mlc.ast_of_luastring(src, file)
|
||||
local func = mlc.function_of_ast(ast)
|
||||
return func
|
||||
end
|
||||
|
||||
function mlc.function_of_luafile (name)
|
||||
local f = io.open(name, 'r')
|
||||
local src = f:read('*a')
|
||||
f:close()
|
||||
return mlc.function_of_luastring(src, "@"..name)
|
||||
end
|
||||
|
||||
_G.mlc = mlc
|
||||
|
||||
--[[
|
||||
-- Can be used with the following code:
|
||||
require "metalua"
|
||||
local ast = mlc.ast_of_luastring(src)
|
||||
local f = mlc.function_of_ast(ast)
|
||||
f()
|
||||
]]
|
||||
@@ -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
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
require 'metalua.base'
|
||||
require 'metalua.table2'
|
||||
require 'metalua.string2'
|
||||
@@ -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
|
||||
@@ -1,380 +0,0 @@
|
||||
---------------------------------------------------------------------
|
||||
----------------------------------------------------------------------
|
||||
--
|
||||
-- Table module extension
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
----------------------------------------------------------------------
|
||||
|
||||
-- todo: table.scan (scan1?) fold1? flip?
|
||||
|
||||
function table.transpose(t)
|
||||
local tt = { }
|
||||
for a, b in pairs(t) do tt[b] = a end
|
||||
return tt
|
||||
end
|
||||
|
||||
function table.iforeach(f, ...)
|
||||
-- assert (type (f) == "function") [wouldn't allow metamethod __call]
|
||||
local nargs = select("#", ...)
|
||||
if nargs==1 then -- Quick iforeach (most common case), just one table arg
|
||||
local t = ...
|
||||
assert (type (t) == "table")
|
||||
for i = 1, #t do
|
||||
local result = f (t[i])
|
||||
-- If the function returns non-false, stop iteration
|
||||
if result then return result end
|
||||
end
|
||||
else -- advanced case: boundaries and/or multiple tables
|
||||
|
||||
-- fargs: arguments fot a single call to f
|
||||
-- first, last: indexes of the first & last elements mapped in each table
|
||||
-- arg1: index of the first table in args
|
||||
|
||||
-- 1 - find boundaries if any
|
||||
local args, fargs, first, last, arg1 = {...}, { }
|
||||
if type(args[1]) ~= "number" then first, arg1 = 1, 1 -- no boundary
|
||||
elseif type(args[2]) ~= "number" then first, last, arg1 = 1, args[1], 2
|
||||
else first, last, arg1 = args[1], args[2], 3 end
|
||||
assert (nargs >= arg1) -- at least one table
|
||||
-- 2 - determine upper boundary if not given
|
||||
if not last then for i = arg1, nargs do
|
||||
assert (type (args[i]) == "table")
|
||||
last = max (#args[i], last)
|
||||
end end
|
||||
-- 3 - remove non-table arguments from args, adjust nargs
|
||||
if arg1>1 then args = { select(arg1, unpack(args)) }; nargs = #args end
|
||||
|
||||
-- 4 - perform the iteration
|
||||
for i = first, last do
|
||||
for j = 1, nargs do fargs[j] = args[j][i] end -- build args list
|
||||
local result = f (unpack (fargs)) -- here is the call
|
||||
-- If the function returns non-false, stop iteration
|
||||
if result then return result end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function table.imap (f, ...)
|
||||
local result, idx = { }, 1
|
||||
local function g(...) result[idx] = f(...); idx=idx+1 end
|
||||
table.iforeach(g, ...)
|
||||
return result
|
||||
end
|
||||
|
||||
function table.ifold (f, acc, ...)
|
||||
local function g(...) acc = f (acc,...) end
|
||||
table.iforeach (g, ...)
|
||||
return acc
|
||||
end
|
||||
|
||||
-- function table.ifold1 (f, ...)
|
||||
-- return table.ifold (f, acc, 2, false, ...)
|
||||
-- end
|
||||
|
||||
function table.izip(...)
|
||||
local function g(...) return {...} end
|
||||
return table.imap(g, ...)
|
||||
end
|
||||
|
||||
function table.ifilter(f, t)
|
||||
local yes, no = { }, { }
|
||||
for i=1,#t do table.insert (f(t[i]) and yes or no, t[i]) end
|
||||
return yes, no
|
||||
end
|
||||
|
||||
function table.icat(...)
|
||||
local result = { }
|
||||
for t in values {...} do
|
||||
for x in values (t) do
|
||||
table.insert (result, x)
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
function table.iflatten (x) return table.icat (unpack (x)) end
|
||||
|
||||
function table.irev (t)
|
||||
local result, nt = { }, #t
|
||||
for i=0, nt-1 do result[nt-i] = t[i+1] end
|
||||
return result
|
||||
end
|
||||
|
||||
function table.isub (t, ...)
|
||||
local ti, u = table.insert, { }
|
||||
local args, nargs = {...}, select("#", ...)
|
||||
for i=1, nargs/2 do
|
||||
local a, b = args[2*i-1], args[2*i]
|
||||
for i=a, b, a<=b and 1 or -1 do ti(u, t[i]) end
|
||||
end
|
||||
return u
|
||||
end
|
||||
|
||||
function table.iall (f, ...)
|
||||
local result = true
|
||||
local function g(...) return not f(...) end
|
||||
return not table.iforeach(g, ...)
|
||||
--return result
|
||||
end
|
||||
|
||||
function table.iany (f, ...)
|
||||
local function g(...) return not f(...) end
|
||||
return not table.iall(g, ...)
|
||||
end
|
||||
|
||||
function table.shallow_copy(x)
|
||||
local y={ }
|
||||
for k, v in pairs(x) do y[k]=v end
|
||||
return y
|
||||
end
|
||||
|
||||
-- Warning, this is implementation dependent: it relies on
|
||||
-- the fact the [next()] enumerates the array-part before the hash-part.
|
||||
function table.cat(...)
|
||||
local y={ }
|
||||
for x in values{...} do
|
||||
-- cat array-part
|
||||
for _, v in ipairs(x) do table.insert(y,v) end
|
||||
-- cat hash-part
|
||||
local lx, k = #x
|
||||
if lx>0 then k=next(x,lx) else k=next(x) end
|
||||
while k do y[k]=x[k]; k=next(x,k) end
|
||||
end
|
||||
return y
|
||||
end
|
||||
|
||||
function table.deep_copy(x)
|
||||
local tracker = { }
|
||||
local function aux (x)
|
||||
if type(x) == "table" then
|
||||
local y=tracker[x]
|
||||
if y then return y end
|
||||
y = { }; tracker[x] = y
|
||||
setmetatable (y, getmetatable (x))
|
||||
for k,v in pairs(x) do y[aux(k)] = aux(v) end
|
||||
return y
|
||||
else return x end
|
||||
end
|
||||
return aux(x)
|
||||
end
|
||||
|
||||
function table.override(dst, src)
|
||||
for k, v in pairs(src) do dst[k] = v end
|
||||
for i = #src+1, #dst do dst[i] = nil end
|
||||
return dst
|
||||
end
|
||||
|
||||
|
||||
function table.range(a,b,c)
|
||||
if not b then assert(not(c)); b=a; a=1
|
||||
elseif not c then c = (b>=a) and 1 or -1 end
|
||||
local result = { }
|
||||
for i=a, b, c do table.insert(result, i) end
|
||||
return result
|
||||
end
|
||||
|
||||
-- FIXME: new_indent seems to be always nil?!
|
||||
-- FIXME: accumulator function should be configurable,
|
||||
-- so that print() doesn't need to bufferize the whole string
|
||||
-- before starting to print.
|
||||
function table.tostring(t, ...)
|
||||
local PRINT_HASH, HANDLE_TAG, FIX_INDENT, LINE_MAX, INITIAL_INDENT = true, true
|
||||
for _, x in ipairs {...} do
|
||||
if type(x) == "number" then
|
||||
if not LINE_MAX then LINE_MAX = x
|
||||
else INITIAL_INDENT = x end
|
||||
elseif x=="nohash" then PRINT_HASH = false
|
||||
elseif x=="notag" then HANDLE_TAG = false
|
||||
else
|
||||
local n = string['match'](x, "^indent%s*(%d*)$")
|
||||
if n then FIX_INDENT = tonumber(n) or 3 end
|
||||
end
|
||||
end
|
||||
LINE_MAX = LINE_MAX or math.huge
|
||||
INITIAL_INDENT = INITIAL_INDENT or 1
|
||||
|
||||
local current_offset = 0 -- indentation level
|
||||
local xlen_cache = { } -- cached results for xlen()
|
||||
local acc_list = { } -- Generated bits of string
|
||||
local function acc(...) -- Accumulate a bit of string
|
||||
local x = table.concat{...}
|
||||
current_offset = current_offset + #x
|
||||
table.insert(acc_list, x)
|
||||
end
|
||||
local function valid_id(x)
|
||||
-- FIXME: we should also reject keywords; but the list of
|
||||
-- current keywords is not fixed in metalua...
|
||||
return type(x) == "string"
|
||||
and string['match'](x, "^[a-zA-Z_][a-zA-Z0-9_]*$")
|
||||
end
|
||||
|
||||
-- Compute the number of chars it would require to display the table
|
||||
-- on a single line. Helps to decide whether some carriage returns are
|
||||
-- required. Since the size of each sub-table is required many times,
|
||||
-- it's cached in [xlen_cache].
|
||||
local xlen_type = { }
|
||||
local function xlen(x, nested)
|
||||
nested = nested or { }
|
||||
if x==nil then return #"nil" end
|
||||
--if nested[x] then return #tostring(x) end -- already done in table
|
||||
local len = xlen_cache[x]
|
||||
if len then return len end
|
||||
local f = xlen_type[type(x)]
|
||||
if not f then return #tostring(x) end
|
||||
len = f (x, nested)
|
||||
xlen_cache[x] = len
|
||||
return len
|
||||
end
|
||||
|
||||
-- optim: no need to compute lengths if I'm not going to use them
|
||||
-- anyway.
|
||||
if LINE_MAX == math.huge then xlen = function() return 0 end end
|
||||
|
||||
xlen_type["nil"] = function () return 3 end
|
||||
function xlen_type.number (x) return #tostring(x) end
|
||||
function xlen_type.boolean (x) return x and 4 or 5 end
|
||||
function xlen_type.string (x) return #string.format("%q",x) end
|
||||
function xlen_type.table (adt, nested)
|
||||
|
||||
-- Circular references detection
|
||||
if nested [adt] then return #tostring(adt) end
|
||||
nested [adt] = true
|
||||
|
||||
local has_tag = HANDLE_TAG and valid_id(adt.tag)
|
||||
local alen = #adt
|
||||
local has_arr = alen>0
|
||||
local has_hash = false
|
||||
local x = 0
|
||||
|
||||
if PRINT_HASH then
|
||||
-- first pass: count hash-part
|
||||
for k, v in pairs(adt) do
|
||||
if k=="tag" and has_tag then
|
||||
-- this is the tag -> do nothing!
|
||||
elseif type(k)=="number" and k<=alen and math.fmod(k,1)==0 then
|
||||
-- array-part pair -> do nothing!
|
||||
else
|
||||
has_hash = true
|
||||
if valid_id(k) then x=x+#k
|
||||
else x = x + xlen (k, nested) + 2 end -- count surrounding brackets
|
||||
x = x + xlen (v, nested) + 5 -- count " = " and ", "
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for i = 1, alen do x = x + xlen (adt[i], nested) + 2 end -- count ", "
|
||||
|
||||
nested[adt] = false -- No more nested calls
|
||||
|
||||
if not (has_tag or has_arr or has_hash) then return 3 end
|
||||
if has_tag then x=x+#adt.tag+1 end
|
||||
if not (has_arr or has_hash) then return x end
|
||||
if not has_hash and alen==1 and type(adt[1])~="table" then
|
||||
return x-2 -- substract extraneous ", "
|
||||
end
|
||||
return x+2 -- count "{ " and " }", substract extraneous ", "
|
||||
end
|
||||
|
||||
-- Recursively print a (sub) table at given indentation level.
|
||||
-- [newline] indicates whether newlines should be inserted.
|
||||
local function rec (adt, nested, indent)
|
||||
if not FIX_INDENT then indent = current_offset end
|
||||
local function acc_newline()
|
||||
acc ("\n"); acc (string.rep (" ", indent))
|
||||
current_offset = indent
|
||||
end
|
||||
local x = { }
|
||||
x["nil"] = function() acc "nil" end
|
||||
function x.number() acc (tostring (adt)) end
|
||||
--function x.string() acc (string.format ("%q", adt)) end
|
||||
function x.string() acc ((string.format ("%q", adt):gsub("\\\n", "\\n"))) end
|
||||
function x.boolean() acc (adt and "true" or "false") end
|
||||
function x.table()
|
||||
if nested[adt] then acc(tostring(adt)); return end
|
||||
nested[adt] = true
|
||||
|
||||
|
||||
local has_tag = HANDLE_TAG and valid_id(adt.tag)
|
||||
local alen = #adt
|
||||
local has_arr = alen>0
|
||||
local has_hash = false
|
||||
|
||||
if has_tag then acc("`"); acc(adt.tag) end
|
||||
|
||||
-- First pass: handle hash-part
|
||||
if PRINT_HASH then
|
||||
for k, v in pairs(adt) do
|
||||
-- pass if the key belongs to the array-part or is the "tag" field
|
||||
if not (k=="tag" and HANDLE_TAG) and
|
||||
not (type(k)=="number" and k<=alen and math.fmod(k,1)==0) then
|
||||
|
||||
-- Is it the first time we parse a hash pair?
|
||||
if not has_hash then
|
||||
acc "{ "
|
||||
if not FIX_INDENT then indent = current_offset end
|
||||
else acc ", " end
|
||||
|
||||
-- Determine whether a newline is required
|
||||
local is_id, expected_len = valid_id(k)
|
||||
if is_id then expected_len = #k + xlen (v, nested) + #" = , "
|
||||
else expected_len = xlen (k, nested) +
|
||||
xlen (v, nested) + #"[] = , " end
|
||||
if has_hash and expected_len + current_offset > LINE_MAX
|
||||
then acc_newline() end
|
||||
|
||||
-- Print the key
|
||||
if is_id then acc(k); acc " = "
|
||||
else acc "["; rec (k, nested, indent+(FIX_INDENT or 0)); acc "] = " end
|
||||
|
||||
-- Print the value
|
||||
rec (v, nested, indent+(FIX_INDENT or 0))
|
||||
has_hash = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Now we know whether there's a hash-part, an array-part, and a tag.
|
||||
-- Tag and hash-part are already printed if they're present.
|
||||
if not has_tag and not has_hash and not has_arr then acc "{ }";
|
||||
elseif has_tag and not has_hash and not has_arr then -- nothing, tag already in acc
|
||||
else
|
||||
assert (has_hash or has_arr)
|
||||
local no_brace = false
|
||||
if has_hash and has_arr then acc ", "
|
||||
elseif has_tag and not has_hash and alen==1 and type(adt[1])~="table" then
|
||||
-- No brace required; don't print "{", remember not to print "}"
|
||||
acc (" "); rec (adt[1], nested, indent+(FIX_INDENT or 0))
|
||||
no_brace = true
|
||||
elseif not has_hash then
|
||||
-- Braces required, but not opened by hash-part handler yet
|
||||
acc "{ "
|
||||
if not FIX_INDENT then indent = current_offset end
|
||||
end
|
||||
|
||||
-- 2nd pass: array-part
|
||||
if not no_brace and has_arr then
|
||||
rec (adt[1], nested, indent+(FIX_INDENT or 0))
|
||||
for i=2, alen do
|
||||
acc ", ";
|
||||
if current_offset + xlen (adt[i], { }) > LINE_MAX
|
||||
then acc_newline() end
|
||||
rec (adt[i], nested, indent+(FIX_INDENT or 0))
|
||||
end
|
||||
end
|
||||
if not no_brace then acc " }" end
|
||||
end
|
||||
nested[adt] = false -- No more nested calls
|
||||
end
|
||||
local y = x[type(adt)]
|
||||
if y then y() else acc(tostring(adt)) end
|
||||
end
|
||||
--printf("INITIAL_INDENT = %i", INITIAL_INDENT)
|
||||
current_offset = INITIAL_INDENT or 0
|
||||
rec(t, { }, 0)
|
||||
return table.concat (acc_list)
|
||||
end
|
||||
|
||||
function table.print(...) return print(table.tostring(...)) end
|
||||
|
||||
return table
|
||||
@@ -1,213 +0,0 @@
|
||||
----------------------------------------------------------------------
|
||||
-- Metalua: $Id: mlp_expr.lua,v 1.7 2006/11/15 09:07:50 fab13n Exp $
|
||||
--
|
||||
-- Summary: metalua parser, expression parser. This is part of the
|
||||
-- definition of module [mlp].
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
--
|
||||
-- Copyright (c) 2006, Fabien Fleutot <metalua@gmail.com>.
|
||||
--
|
||||
-- This software is released under the MIT Licence, see licence.txt
|
||||
-- for details.
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
-- History:
|
||||
-- $Log: mlp_expr.lua,v $
|
||||
-- Revision 1.7 2006/11/15 09:07:50 fab13n
|
||||
-- debugged meta operators.
|
||||
-- Added command line options handling.
|
||||
--
|
||||
-- Revision 1.6 2006/11/10 02:11:17 fab13n
|
||||
-- compiler faithfulness to 5.1 improved
|
||||
-- gg.expr extended
|
||||
-- mlp.expr refactored
|
||||
--
|
||||
-- Revision 1.5 2006/11/09 09:39:57 fab13n
|
||||
-- some cleanup
|
||||
--
|
||||
-- Revision 1.4 2006/11/07 21:29:02 fab13n
|
||||
-- improved quasi-quoting
|
||||
--
|
||||
-- Revision 1.3 2006/11/07 04:38:00 fab13n
|
||||
-- first bootstrapping version.
|
||||
--
|
||||
-- Revision 1.2 2006/11/05 15:08:34 fab13n
|
||||
-- updated code generation, to be compliant with 5.1
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
--
|
||||
-- Exported API:
|
||||
-- * [mlp.expr()]
|
||||
-- * [mlp.expr_list()]
|
||||
-- * [mlp.func_val()]
|
||||
--
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
--require "gg"
|
||||
--require "mlp_misc"
|
||||
--require "mlp_table"
|
||||
--require "mlp_meta"
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- These function wrappers (eta-expansions ctually) are just here to break
|
||||
-- some circular dependencies between mlp_xxx.lua files.
|
||||
--------------------------------------------------------------------------------
|
||||
local function _expr (lx) return mlp.expr (lx) end
|
||||
local function _table_content (lx) return mlp.table_content (lx) end
|
||||
local function block (lx) return mlp.block (lx) end
|
||||
local function stat (lx) return mlp.stat (lx) end
|
||||
|
||||
module ("mlp", package.seeall)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Non-empty expression list. Actually, this isn't used here, but that's
|
||||
-- handy to give to users.
|
||||
--------------------------------------------------------------------------------
|
||||
expr_list = gg.list{ _expr, separators = "," }
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Helpers for function applications / method applications
|
||||
--------------------------------------------------------------------------------
|
||||
func_args_content = gg.list {
|
||||
name = "function arguments",
|
||||
_expr, separators = ",", terminators = ")" }
|
||||
|
||||
-- Used to parse methods
|
||||
method_args = gg.multisequence{
|
||||
name = "function argument(s)",
|
||||
{ "{", table_content, "}" },
|
||||
{ "(", func_args_content, ")", builder = fget(1) },
|
||||
{ "+{", quote_content, "}" },
|
||||
function(lx) local r = opt_string(lx); return r and {r} or { } end }
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- [func_val] parses a function, from opening parameters parenthese to
|
||||
-- "end" keyword included. Used for anonymous functions as well as
|
||||
-- function declaration statements (both local and global).
|
||||
--
|
||||
-- It's wrapped in a [_func_val] eta expansion, so that when expr
|
||||
-- parser uses the latter, they will notice updates of [func_val]
|
||||
-- definitions.
|
||||
--------------------------------------------------------------------------------
|
||||
func_params_content = gg.list{ name="function parameters",
|
||||
gg.multisequence{ { "...", builder = "Dots" }, id },
|
||||
separators = ",", terminators = {")", "|"} }
|
||||
|
||||
local _func_params_content = function (lx) return func_params_content(lx) end
|
||||
|
||||
func_val = gg.sequence { name="function body",
|
||||
"(", func_params_content, ")", block, "end", builder = "Function" }
|
||||
|
||||
local _func_val = function (lx) return func_val(lx) end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Default parser for primary expressions
|
||||
--------------------------------------------------------------------------------
|
||||
function id_or_literal (lx)
|
||||
local a = lx:next()
|
||||
if a.tag~="Id" and a.tag~="String" and a.tag~="Number" then
|
||||
local msg
|
||||
if a.tag=='Eof' then
|
||||
msg = "End of file reached when an expression was expected"
|
||||
elseif a.tag=='Keyword' then
|
||||
msg = "An expression was expected, and `"..a[1]..
|
||||
"' can't start an expression"
|
||||
else
|
||||
msg = "Unexpected expr token " .. _G.table.tostring (a, 'nohash')
|
||||
end
|
||||
gg.parse_error (lx, msg)
|
||||
end
|
||||
return a
|
||||
end
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Builder generator for operators. Wouldn't be worth it if "|x|" notation
|
||||
-- were allowed, but then lua 5.1 wouldn't compile it
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
-- opf1 = |op| |_,a| `Op{ op, a }
|
||||
local function opf1 (op) return
|
||||
function (_,a) return { tag="Op", op, a } end end
|
||||
|
||||
-- opf2 = |op| |a,_,b| `Op{ op, a, b }
|
||||
local function opf2 (op) return
|
||||
function (a,_,b) return { tag="Op", op, a, b } end end
|
||||
|
||||
-- opf2r = |op| |a,_,b| `Op{ op, b, a } -- (args reversed)
|
||||
local function opf2r (op) return
|
||||
function (a,_,b) return { tag="Op", op, b, a } end end
|
||||
|
||||
local function op_ne(a, _, b)
|
||||
-- The first version guarantees to return the same code as Lua,
|
||||
-- but it relies on the non-standard 'ne' operator, which has been
|
||||
-- suppressed from the official AST grammar (although still supported
|
||||
-- in practice by the compiler).
|
||||
-- return { tag="Op", "ne", a, b }
|
||||
return { tag="Op", "not", { tag="Op", "eq", a, b, lineinfo= {
|
||||
first = a.lineinfo.first, last = b.lineinfo.last } } }
|
||||
end
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
--
|
||||
-- complete expression
|
||||
--
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
-- FIXME: set line number. In [expr] transformers probably
|
||||
|
||||
expr = gg.expr { name = "expression",
|
||||
|
||||
primary = gg.multisequence{ name="expr primary",
|
||||
{ "(", _expr, ")", builder = "Paren" },
|
||||
{ "function", _func_val, builder = fget(1) },
|
||||
{ "-{", splice_content, "}", builder = fget(1) },
|
||||
{ "+{", quote_content, "}", builder = fget(1) },
|
||||
{ "nil", builder = "Nil" },
|
||||
{ "true", builder = "True" },
|
||||
{ "false", builder = "False" },
|
||||
{ "...", builder = "Dots" },
|
||||
table,
|
||||
id_or_literal },
|
||||
|
||||
infix = { name="expr infix op",
|
||||
{ "+", prec = 60, builder = opf2 "add" },
|
||||
{ "-", prec = 60, builder = opf2 "sub" },
|
||||
{ "*", prec = 70, builder = opf2 "mul" },
|
||||
{ "/", prec = 70, builder = opf2 "div" },
|
||||
{ "%", prec = 70, builder = opf2 "mod" },
|
||||
{ "^", prec = 90, builder = opf2 "pow", assoc = "right" },
|
||||
{ "..", prec = 40, builder = opf2 "concat", assoc = "right" },
|
||||
{ "==", prec = 30, builder = opf2 "eq" },
|
||||
{ "~=", prec = 30, builder = op_ne },
|
||||
{ "<", prec = 30, builder = opf2 "lt" },
|
||||
{ "<=", prec = 30, builder = opf2 "le" },
|
||||
{ ">", prec = 30, builder = opf2r "lt" },
|
||||
{ ">=", prec = 30, builder = opf2r "le" },
|
||||
{ "and",prec = 20, builder = opf2 "and" },
|
||||
{ "or", prec = 10, builder = opf2 "or" } },
|
||||
|
||||
prefix = { name="expr prefix op",
|
||||
{ "not", prec = 80, builder = opf1 "not" },
|
||||
{ "#", prec = 80, builder = opf1 "len" },
|
||||
{ "-", prec = 80, builder = opf1 "unm" } },
|
||||
|
||||
suffix = { name="expr suffix op",
|
||||
{ "[", _expr, "]", builder = function (tab, idx)
|
||||
return {tag="Index", tab, idx[1]} end},
|
||||
{ ".", id, builder = function (tab, field)
|
||||
return {tag="Index", tab, id2string(field[1])} end },
|
||||
{ "(", func_args_content, ")", builder = function(f, args)
|
||||
return {tag="Call", f, unpack(args[1])} end },
|
||||
{ "{", _table_content, "}", builder = function (f, arg)
|
||||
return {tag="Call", f, arg[1]} end},
|
||||
{ ":", id, method_args, builder = function (obj, post)
|
||||
return {tag="Invoke", obj, id2string(post[1]), unpack(post[2])} end},
|
||||
{ "+{", quote_content, "}", builder = function (f, arg)
|
||||
return {tag="Call", f, arg[1] } end },
|
||||
default = { name="opt_string_arg", parse = mlp.opt_string, builder = function(f, arg)
|
||||
return {tag="Call", f, arg } end } } }
|
||||
@@ -1,89 +0,0 @@
|
||||
--------------------------------------------------------------------------------
|
||||
--
|
||||
-- Non-Lua syntax extensions
|
||||
--
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
module ("mlp", package.seeall)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Alebraic Datatypes
|
||||
--------------------------------------------------------------------------------
|
||||
local function adt (lx)
|
||||
local tagval = id (lx) [1]
|
||||
local tagkey = {tag="Pair", {tag="String", "tag"}, {tag="String", tagval} }
|
||||
if lx:peek().tag == "String" or lx:peek().tag == "Number" then
|
||||
return { tag="Table", tagkey, lx:next() }
|
||||
elseif lx:is_keyword (lx:peek(), "{") then
|
||||
local x = table (lx)
|
||||
_G.table.insert (x, 1, tagkey)
|
||||
return x
|
||||
else return { tag="Table", tagkey } end
|
||||
end
|
||||
|
||||
expr:add{ "`", adt, builder = fget(1) }
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Anonymous lambda
|
||||
--------------------------------------------------------------------------------
|
||||
local lambda_expr = gg.sequence{
|
||||
"|", func_params_content, "|", expr,
|
||||
builder= function (x)
|
||||
local li = x[2].lineinfo
|
||||
return { tag="Function", x[1],
|
||||
{ {tag="Return", x[2], lineinfo=li }, lineinfo=li } }
|
||||
end }
|
||||
|
||||
-- In an earlier version, lambda_expr took an expr_list rather than an expr
|
||||
-- after the 2nd bar. However, it happened to be much more of a burden than an
|
||||
-- help, So finally I disabled it. If you want to return several results,
|
||||
-- use the long syntax.
|
||||
--------------------------------------------------------------------------------
|
||||
-- local lambda_expr = gg.sequence{
|
||||
-- "|", func_params_content, "|", expr_list,
|
||||
-- builder= function (x)
|
||||
-- return {tag="Function", x[1], { {tag="Return", unpack(x[2]) } } } end }
|
||||
|
||||
expr:add (lambda_expr)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Allows to write "a `f` b" instead of "f(a, b)". Taken from Haskell.
|
||||
-- This is not part of Lua 5.1 syntax, so it's added to the expression
|
||||
-- afterwards, so that it's easier to disable.
|
||||
--------------------------------------------------------------------------------
|
||||
local function expr_in_backquotes (lx) return expr(lx, 35) end
|
||||
|
||||
expr.infix:add{ name = "infix function",
|
||||
"`", expr_in_backquotes, "`", prec = 35, assoc="left",
|
||||
builder = function(a, op, b) return {tag="Call", op[1], a, b} end }
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- table.override assignment
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
mlp.lexer:add "<-"
|
||||
stat.assignments["<-"] = function (a, b)
|
||||
assert( #a==1 and #b==1, "No multi-args for '<-'")
|
||||
return { tag="Call", { tag="Index", { tag="Id", "table" },
|
||||
{ tag="String", "override" } },
|
||||
a[1], b[1]}
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- C-style op+assignments
|
||||
--------------------------------------------------------------------------------
|
||||
local function op_assign(kw, op)
|
||||
local function rhs(a, b)
|
||||
return { tag="Op", op, a, b }
|
||||
end
|
||||
local function f(a,b)
|
||||
return { tag="Set", a, _G.table.imap(rhs, a, b) }
|
||||
end
|
||||
mlp.lexer:add (kw)
|
||||
mlp.stat.assignments[kw] = f
|
||||
end
|
||||
|
||||
_G.table.iforeach (op_assign,
|
||||
{"+=", "-=", "*=", "/="},
|
||||
{"add", "sub", "mul", "div"})
|
||||
@@ -1,32 +0,0 @@
|
||||
----------------------------------------------------------------------
|
||||
-- Metalua: $Id: mll.lua,v 1.3 2006/11/15 09:07:50 fab13n Exp $
|
||||
--
|
||||
-- Summary: Source file lexer. ~~Currently only works on strings.
|
||||
-- Some API refactoring is needed.
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
--
|
||||
-- Copyright (c) 2006-2007, Fabien Fleutot <metalua@gmail.com>.
|
||||
--
|
||||
-- This software is released under the MIT Licence, see licence.txt
|
||||
-- for details.
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
|
||||
module ("mlp", package.seeall)
|
||||
|
||||
require "lexer"
|
||||
|
||||
local mlp_lexer = lexer.lexer:clone()
|
||||
|
||||
local keywords = {
|
||||
"and", "break", "do", "else", "elseif",
|
||||
"end", "false", "for", "function", "if",
|
||||
"in", "local", "nil", "not", "or", "repeat",
|
||||
"return", "then", "true", "until", "while",
|
||||
"...", "..", "==", ">=", "<=", "~=",
|
||||
"+{", "-{" }
|
||||
|
||||
for _,w in pairs(keywords) do mlp_lexer:add(w) end -- PK 6/4/2012
|
||||
|
||||
_M.lexer = mlp_lexer
|
||||
@@ -1,118 +0,0 @@
|
||||
----------------------------------------------------------------------
|
||||
-- Metalua: $Id: mlp_meta.lua,v 1.4 2006/11/15 09:07:50 fab13n Exp $
|
||||
--
|
||||
-- Summary: Meta-operations: AST quasi-quoting and splicing
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
--
|
||||
-- Copyright (c) 2006, Fabien Fleutot <metalua@gmail.com>.
|
||||
--
|
||||
-- This software is released under the MIT Licence, see licence.txt
|
||||
-- for details.
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
--
|
||||
-- Exported API:
|
||||
-- * [mlp.splice_content()]
|
||||
-- * [mlp.quote_content()]
|
||||
--
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
module ("mlp", package.seeall)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- External splicing: compile an AST into a chunk, load and evaluate
|
||||
-- that chunk, and replace the chunk by its result (which must also be
|
||||
-- an AST).
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
function splice (ast)
|
||||
local f = mlc.function_of_ast(ast, '=splice')
|
||||
local result=f()
|
||||
return result
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Going from an AST to an AST representing that AST
|
||||
-- the only key being lifted in this version is ["tag"]
|
||||
--------------------------------------------------------------------------------
|
||||
function quote (t)
|
||||
--print("QUOTING:", _G.table.tostring(t, 60))
|
||||
local cases = { }
|
||||
function cases.table (t)
|
||||
local mt = { tag = "Table" }
|
||||
--_G.table.insert (mt, { tag = "Pair", quote "quote", { tag = "True" } })
|
||||
if t.tag == "Splice" then
|
||||
assert (#t==1, "Invalid splice")
|
||||
local sp = t[1]
|
||||
return sp
|
||||
elseif t.tag then
|
||||
_G.table.insert (mt, { tag = "Pair", quote "tag", quote (t.tag) })
|
||||
end
|
||||
for _, v in ipairs (t) do
|
||||
_G.table.insert (mt, quote(v))
|
||||
end
|
||||
return mt
|
||||
end
|
||||
function cases.number (t) return { tag = "Number", t, quote = true } end
|
||||
function cases.string (t) return { tag = "String", t, quote = true } end
|
||||
return cases [ type (t) ] (t)
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- when this variable is false, code inside [-{...}] is compiled and
|
||||
-- avaluated immediately. When it's true (supposedly when we're
|
||||
-- parsing data inside a quasiquote), [-{foo}] is replaced by
|
||||
-- [`Splice{foo}], which will be unpacked by [quote()].
|
||||
--------------------------------------------------------------------------------
|
||||
in_a_quote = false
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Parse the inside of a "-{ ... }"
|
||||
--------------------------------------------------------------------------------
|
||||
function splice_content (lx)
|
||||
local parser_name = "expr"
|
||||
if lx:is_keyword (lx:peek(2), ":") then
|
||||
local a = lx:next()
|
||||
lx:next() -- skip ":"
|
||||
assert (a.tag=="Id", "Invalid splice parser name")
|
||||
parser_name = a[1]
|
||||
end
|
||||
local ast = mlp[parser_name](lx)
|
||||
if in_a_quote then
|
||||
--printf("SPLICE_IN_QUOTE:\n%s", _G.table.tostring(ast, "nohash", 60))
|
||||
return { tag="Splice", ast }
|
||||
else
|
||||
if parser_name == "expr" then ast = { { tag="Return", ast } }
|
||||
elseif parser_name == "stat" then ast = { ast }
|
||||
elseif parser_name ~= "block" then
|
||||
error ("splice content must be an expr, stat or block") end
|
||||
--printf("EXEC THIS SPLICE:\n%s", _G.table.tostring(ast, "nohash", 60))
|
||||
return splice (ast)
|
||||
end
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Parse the inside of a "+{ ... }"
|
||||
--------------------------------------------------------------------------------
|
||||
function quote_content (lx)
|
||||
local parser
|
||||
if lx:is_keyword (lx:peek(2), ":") then -- +{parser: content }
|
||||
parser = mlp[id(lx)[1]]
|
||||
lx:next()
|
||||
else -- +{ content }
|
||||
parser = mlp.expr
|
||||
end
|
||||
|
||||
local prev_iq = in_a_quote
|
||||
in_a_quote = true
|
||||
--print("IN_A_QUOTE")
|
||||
local content = parser (lx)
|
||||
local q_content = quote (content)
|
||||
in_a_quote = prev_iq
|
||||
return q_content
|
||||
end
|
||||
|
||||
@@ -1,185 +0,0 @@
|
||||
----------------------------------------------------------------------
|
||||
-- Metalua: $Id: mlp_misc.lua,v 1.6 2006/11/15 09:07:50 fab13n Exp $
|
||||
--
|
||||
-- Summary: metalua parser, miscellaneous utility functions.
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
--
|
||||
-- Copyright (c) 2006, Fabien Fleutot <metalua@gmail.com>.
|
||||
--
|
||||
-- This software is released under the MIT Licence, see licence.txt
|
||||
-- for details.
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
-- History:
|
||||
-- $Log: mlp_misc.lua,v $
|
||||
-- Revision 1.6 2006/11/15 09:07:50 fab13n
|
||||
-- debugged meta operators.
|
||||
-- Added command line options handling.
|
||||
--
|
||||
-- Revision 1.5 2006/11/10 02:11:17 fab13n
|
||||
-- compiler faithfulness to 5.1 improved
|
||||
-- gg.expr extended
|
||||
-- mlp.expr refactored
|
||||
--
|
||||
-- Revision 1.4 2006/11/09 09:39:57 fab13n
|
||||
-- some cleanup
|
||||
--
|
||||
-- Revision 1.3 2006/11/07 04:38:00 fab13n
|
||||
-- first bootstrapping version.
|
||||
--
|
||||
-- Revision 1.2 2006/11/05 15:08:34 fab13n
|
||||
-- updated code generation, to be compliant with 5.1
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
--
|
||||
-- Exported API:
|
||||
-- * [mlp.fget()]
|
||||
-- * [mlp.id()]
|
||||
-- * [mlp.opt_id()]
|
||||
-- * [mlp.id_list()]
|
||||
-- * [mlp.gensym()]
|
||||
-- * [mlp.string()]
|
||||
-- * [mlp.opt_string()]
|
||||
-- * [mlp.id2string()]
|
||||
--
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
--require "gg"
|
||||
--require "mll"
|
||||
|
||||
module ("mlp", package.seeall)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- returns a function that takes the [n]th element of a table.
|
||||
-- if [tag] is provided, then this element is expected to be a
|
||||
-- table, and this table receives a "tag" field whose value is
|
||||
-- set to [tag].
|
||||
--
|
||||
-- The primary purpose of this is to generate builders for
|
||||
-- grammar generators. It has little purpose in metalua, as lambda has
|
||||
-- a lightweight syntax.
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
function fget (n, tag)
|
||||
assert (type (n) == "number")
|
||||
if tag then
|
||||
assert (type (tag) == "string")
|
||||
return function (x)
|
||||
assert (type (x[n]) == "table")
|
||||
return {tag=tag, unpack(x[n])} end
|
||||
else
|
||||
return function (x) return x[n] end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Try to read an identifier (possibly as a splice), or return [false] if no
|
||||
-- id is found.
|
||||
--------------------------------------------------------------------------------
|
||||
function opt_id (lx)
|
||||
local a = lx:peek();
|
||||
if lx:is_keyword (a, "-{") then
|
||||
local v = gg.sequence{ "-{", splice_content, "}" } (lx) [1]
|
||||
if v.tag ~= "Id" and v.tag ~= "Splice" then
|
||||
gg.parse_error(lx,"Bad id splice")
|
||||
end
|
||||
return v
|
||||
elseif a.tag == "Id" then return lx:next()
|
||||
else return false end
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Mandatory reading of an id: causes an error if it can't read one.
|
||||
--------------------------------------------------------------------------------
|
||||
function id (lx)
|
||||
return opt_id (lx) or gg.parse_error(lx,"Identifier expected")
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Common helper function
|
||||
--------------------------------------------------------------------------------
|
||||
id_list = gg.list { primary = mlp.id, separators = "," }
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Symbol generator: [gensym()] returns a guaranteed-to-be-unique identifier.
|
||||
-- The main purpose is to avoid variable capture in macros.
|
||||
--
|
||||
-- If a string is passed as an argument, theis string will be part of the
|
||||
-- id name (helpful for macro debugging)
|
||||
--------------------------------------------------------------------------------
|
||||
local gensymidx = 0
|
||||
|
||||
function gensym (arg)
|
||||
gensymidx = gensymidx + 1
|
||||
return { tag="Id", _G.string.format(".%i.%s", gensymidx, arg or "")}
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Converts an identifier into a string. Hopefully one day it'll handle
|
||||
-- splices gracefully, but that proves quite tricky.
|
||||
--------------------------------------------------------------------------------
|
||||
function id2string (id)
|
||||
--print("id2string:", disp.ast(id))
|
||||
if id.tag == "Id" then id.tag = "String"; return id
|
||||
elseif id.tag == "Splice" then
|
||||
assert (in_a_quote, "can't do id2string on an outermost splice")
|
||||
error ("id2string on splice not implemented")
|
||||
-- Evaluating id[1] will produce `Id{ xxx },
|
||||
-- and we want it to produce `String{ xxx }
|
||||
-- Morally, this is what I want:
|
||||
-- return `String{ `Index{ `Splice{ id[1] }, `Number 1 } }
|
||||
-- That is, without sugar:
|
||||
return {tag="String", {tag="Index", {tag="Splice", id[1] },
|
||||
{tag="Number", 1 } } }
|
||||
else error ("Identifier expected: ".._G.table.tostring(id, 'nohash')) end
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Read a string, possibly spliced, or return an error if it can't
|
||||
--------------------------------------------------------------------------------
|
||||
function string (lx)
|
||||
local a = lx:peek()
|
||||
if lx:is_keyword (a, "-{") then
|
||||
local v = gg.sequence{ "-{", splice_content, "}" } (lx) [1]
|
||||
if v.tag ~= "" and v.tag ~= "Splice" then
|
||||
gg.parse_error(lx,"Bad string splice")
|
||||
end
|
||||
return v
|
||||
elseif a.tag == "String" then return lx:next()
|
||||
else error "String expected" end
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Try to read a string, or return false if it can't. No splice allowed.
|
||||
--------------------------------------------------------------------------------
|
||||
function opt_string (lx)
|
||||
return lx:peek().tag == "String" and lx:next()
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Chunk reader: block + Eof
|
||||
--------------------------------------------------------------------------------
|
||||
function skip_initial_sharp_comment (lx)
|
||||
-- Dirty hack: I'm happily fondling lexer's private parts
|
||||
-- FIXME: redundant with lexer:newstream()
|
||||
lx :sync()
|
||||
local i = lx.src:match ("^#.-\n()", lx.i)
|
||||
if i then lx.i, lx.column_offset, lx.line = i, i, lx.line+1 end
|
||||
end
|
||||
|
||||
local function _chunk (lx)
|
||||
if lx:peek().tag == 'Eof' then return { } -- handle empty files
|
||||
else
|
||||
skip_initial_sharp_comment (lx)
|
||||
local chunk = block (lx)
|
||||
if lx:peek().tag ~= "Eof" then error "End-of-file expected" end
|
||||
return chunk
|
||||
end
|
||||
end
|
||||
|
||||
-- chunk is wrapped in a sequence so that it has a "transformer" field.
|
||||
chunk = gg.sequence { _chunk, builder = unpack }
|
||||
@@ -1,226 +0,0 @@
|
||||
----------------------------------------------------------------------
|
||||
-- Metalua: $Id: mlp_stat.lua,v 1.7 2006/11/15 09:07:50 fab13n Exp $
|
||||
--
|
||||
-- Summary: metalua parser, statement/block parser. This is part of
|
||||
-- the definition of module [mlp].
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
--
|
||||
-- Copyright (c) 2006, Fabien Fleutot <metalua@gmail.com>.
|
||||
--
|
||||
-- This software is released under the MIT Licence, see licence.txt
|
||||
-- for details.
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
--
|
||||
-- Exports API:
|
||||
-- * [mlp.stat()]
|
||||
-- * [mlp.block()]
|
||||
-- * [mlp.for_header()]
|
||||
--
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- eta-expansions to break circular dependency
|
||||
--------------------------------------------------------------------------------
|
||||
local expr = function (lx) return mlp.expr (lx) end
|
||||
local func_val = function (lx) return mlp.func_val (lx) end
|
||||
local expr_list = function (lx) return mlp.expr_list(lx) end
|
||||
|
||||
module ("mlp", package.seeall)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- List of all keywords that indicate the end of a statement block. Users are
|
||||
-- likely to extend this list when designing extensions.
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
||||
local block_terminators = { "else", "elseif", "end", "until", ")", "}", "]" }
|
||||
|
||||
-- FIXME: this must be handled from within GG!!!
|
||||
function block_terminators:add(x)
|
||||
if type (x) == "table" then for _, y in ipairs(x) do self:add (y) end
|
||||
else _G.table.insert (self, x) end
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- list of statements, possibly followed by semicolons
|
||||
--------------------------------------------------------------------------------
|
||||
block = gg.list {
|
||||
name = "statements block",
|
||||
terminators = block_terminators,
|
||||
primary = function (lx)
|
||||
-- FIXME use gg.optkeyword()
|
||||
local x = stat (lx)
|
||||
if lx:is_keyword (lx:peek(), ";") then lx:next() end
|
||||
return x
|
||||
end }
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Helper function for "return <expr_list>" parsing.
|
||||
-- Called when parsing return statements.
|
||||
-- The specific test for initial ";" is because it's not a block terminator,
|
||||
-- so without itgg.list would choke on "return ;" statements.
|
||||
-- We don't make a modified copy of block_terminators because this list
|
||||
-- is sometimes modified at runtime, and the return parser would get out of
|
||||
-- sync if it was relying on a copy.
|
||||
--------------------------------------------------------------------------------
|
||||
local return_expr_list_parser = gg.multisequence{
|
||||
{ ";" , builder = function() return { } end },
|
||||
default = gg.list {
|
||||
expr, separators = ",", terminators = block_terminators } }
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- for header, between [for] and [do] (exclusive).
|
||||
-- Return the `Forxxx{...} AST, without the body element (the last one).
|
||||
--------------------------------------------------------------------------------
|
||||
function for_header (lx)
|
||||
local var = mlp.id (lx)
|
||||
if lx:is_keyword (lx:peek(), "=") then
|
||||
-- Fornum: only 1 variable
|
||||
lx:next() -- skip "="
|
||||
local e = expr_list (lx)
|
||||
assert (2 <= #e and #e <= 3, "2 or 3 values in a fornum")
|
||||
return { tag="Fornum", var, unpack (e) }
|
||||
else
|
||||
-- Forin: there might be several vars
|
||||
local a = lx:is_keyword (lx:next(), ",", "in")
|
||||
if a=="in" then var_list = { var, lineinfo = var.lineinfo } else
|
||||
-- several vars; first "," skipped, read other vars
|
||||
var_list = gg.list{
|
||||
primary = id, separators = ",", terminators = "in" } (lx)
|
||||
_G.table.insert (var_list, 1, var) -- put back the first variable
|
||||
lx:next() -- skip "in"
|
||||
end
|
||||
local e = expr_list (lx)
|
||||
return { tag="Forin", var_list, e }
|
||||
end
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Function def parser helper: id ( . id ) *
|
||||
--------------------------------------------------------------------------------
|
||||
local function fn_builder (list)
|
||||
local r = list[1]
|
||||
for i = 2, #list do r = { tag="Index", r, id2string(list[i]) } end
|
||||
return r
|
||||
end
|
||||
local func_name = gg.list{ id, separators = ".", builder = fn_builder }
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Function def parser helper: ( : id )?
|
||||
--------------------------------------------------------------------------------
|
||||
local method_name = gg.onkeyword{ name = "method invocation", ":", id,
|
||||
transformers = { function(x) return x and id2string(x) end } }
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Function def builder
|
||||
--------------------------------------------------------------------------------
|
||||
local function funcdef_builder(x)
|
||||
local name, method, func = x[1], x[2], x[3]
|
||||
if method then
|
||||
name = { tag="Index", name, method, lineinfo = {
|
||||
first = name.lineinfo.first,
|
||||
last = method.lineinfo.last } }
|
||||
_G.table.insert (func[1], 1, {tag="Id", "self"})
|
||||
end
|
||||
local r = { tag="Set", {name}, {func} }
|
||||
r[1].lineinfo = name.lineinfo
|
||||
r[2].lineinfo = func.lineinfo
|
||||
return r
|
||||
end
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- if statement builder
|
||||
--------------------------------------------------------------------------------
|
||||
local function if_builder (x)
|
||||
local cb_pairs, else_block, r = x[1], x[2], {tag="If"}
|
||||
for i=1,#cb_pairs do r[2*i-1]=cb_pairs[i][1]; r[2*i]=cb_pairs[i][2] end
|
||||
if else_block then r[#r+1] = else_block end
|
||||
return r
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- produce a list of (expr,block) pairs
|
||||
--------------------------------------------------------------------------------
|
||||
local elseifs_parser = gg.list {
|
||||
gg.sequence { expr, "then", block },
|
||||
separators = "elseif",
|
||||
terminators = { "else", "end" } }
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- assignments and calls: statements that don't start with a keyword
|
||||
--------------------------------------------------------------------------------
|
||||
local function assign_or_call_stat_parser (lx)
|
||||
local e = expr_list (lx)
|
||||
local a = lx:is_keyword(lx:peek())
|
||||
local op = a and stat.assignments[a]
|
||||
if op then
|
||||
--FIXME: check that [e] is a LHS
|
||||
lx:next()
|
||||
local v = expr_list (lx)
|
||||
if type(op)=="string" then return { tag=op, e, v }
|
||||
else return op (e, v) end
|
||||
else
|
||||
assert (#e > 0)
|
||||
if #e > 1 then
|
||||
gg.parse_error (lx,
|
||||
"comma is not a valid statement separator; statement can be "..
|
||||
"separated by semicolons, or not separated at all") end
|
||||
if e[1].tag ~= "Call" and e[1].tag ~= "Invoke" then
|
||||
local typename
|
||||
if e[1].tag == 'Id' then
|
||||
typename = '("'..e[1][1]..'") is an identifier'
|
||||
elseif e[1].tag == 'Op' then
|
||||
typename = "is an arithmetic operation"
|
||||
else typename = "is of type '"..(e[1].tag or "<list>").."'" end
|
||||
|
||||
gg.parse_error (lx, "This expression " .. typename ..
|
||||
"; a statement was expected, and only function and method call "..
|
||||
"expressions can be used as statements");
|
||||
end
|
||||
return e[1]
|
||||
end
|
||||
end
|
||||
|
||||
local_stat_parser = gg.multisequence{
|
||||
-- local function <name> <func_val>
|
||||
{ "function", id, func_val, builder =
|
||||
function(x)
|
||||
local vars = { x[1], lineinfo = x[1].lineinfo }
|
||||
local vals = { x[2], lineinfo = x[2].lineinfo }
|
||||
return { tag="Localrec", vars, vals }
|
||||
end },
|
||||
-- local <id_list> ( = <expr_list> )?
|
||||
default = gg.sequence{ id_list, gg.onkeyword{ "=", expr_list },
|
||||
builder = function(x) return {tag="Local", x[1], x[2] or { } } end } }
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- statement
|
||||
--------------------------------------------------------------------------------
|
||||
stat = gg.multisequence {
|
||||
name="statement",
|
||||
{ "do", block, "end", builder =
|
||||
function (x) return { tag="Do", unpack (x[1]) } end },
|
||||
{ "for", for_header, "do", block, "end", builder =
|
||||
function (x) x[1][#x[1]+1] = x[2]; return x[1] end },
|
||||
{ "function", func_name, method_name, func_val, builder=funcdef_builder },
|
||||
{ "while", expr, "do", block, "end", builder = "While" },
|
||||
{ "repeat", block, "until", expr, builder = "Repeat" },
|
||||
{ "local", local_stat_parser, builder = fget (1) },
|
||||
{ "return", return_expr_list_parser, builder = fget (1, "Return") },
|
||||
{ "break", builder = function() return { tag="Break" } end },
|
||||
{ "-{", splice_content, "}", builder = fget(1) },
|
||||
{ "if", elseifs_parser, gg.onkeyword{ "else", block }, "end",
|
||||
builder = if_builder },
|
||||
default = assign_or_call_stat_parser }
|
||||
|
||||
stat.assignments = {
|
||||
["="] = "Set" }
|
||||
|
||||
function stat.assignments:add(k, v) self[k] = v end
|
||||
@@ -1,92 +0,0 @@
|
||||
----------------------------------------------------------------------
|
||||
-- Metalua: $Id: mlp_table.lua,v 1.5 2006/11/10 02:11:17 fab13n Exp $
|
||||
--
|
||||
-- Summary: metalua parser, table constructor parser. This is part
|
||||
-- of thedefinition of module [mlp].
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
--
|
||||
-- Copyright (c) 2006, Fabien Fleutot <metalua@gmail.com>.
|
||||
--
|
||||
-- This software is released under the MIT Licence, see licence.txt
|
||||
-- for details.
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
-- History:
|
||||
-- $Log: mlp_table.lua,v $
|
||||
-- Revision 1.5 2006/11/10 02:11:17 fab13n
|
||||
-- compiler faithfulness to 5.1 improved
|
||||
-- gg.expr extended
|
||||
-- mlp.expr refactored
|
||||
--
|
||||
-- Revision 1.4 2006/11/09 09:39:57 fab13n
|
||||
-- some cleanup
|
||||
--
|
||||
-- Revision 1.3 2006/11/07 04:38:00 fab13n
|
||||
-- first bootstrapping version.
|
||||
--
|
||||
-- Revision 1.2 2006/11/05 15:08:34 fab13n
|
||||
-- updated code generation, to be compliant with 5.1
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
--
|
||||
-- Exported API:
|
||||
-- * [mlp.table_field()]
|
||||
-- * [mlp.table_content()]
|
||||
-- * [mlp.table()]
|
||||
--
|
||||
-- KNOWN BUG: doesn't handle final ";" or "," before final "}"
|
||||
--
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
--require "gg"
|
||||
--require "mll"
|
||||
--require "mlp_misc"
|
||||
|
||||
module ("mlp", package.seeall)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- eta expansion to break circular dependencies:
|
||||
--------------------------------------------------------------------------------
|
||||
local function _expr (lx) return expr(lx) end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- [[key] = value] table field definition
|
||||
--------------------------------------------------------------------------------
|
||||
local bracket_field = gg.sequence{ "[", _expr, "]", "=", _expr, builder = "Pair" }
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- [id = value] or [value] table field definition;
|
||||
-- [[key]=val] are delegated to [bracket_field()]
|
||||
--------------------------------------------------------------------------------
|
||||
function table_field (lx)
|
||||
if lx:is_keyword (lx:peek(), "[") then return bracket_field (lx) end
|
||||
local e = _expr (lx)
|
||||
if lx:is_keyword (lx:peek(), "=") then
|
||||
lx:next(); -- skip the "="
|
||||
local key = id2string(e)
|
||||
local val = _expr(lx)
|
||||
local r = { tag="Pair", key, val }
|
||||
r.lineinfo = { first = key.lineinfo.first, last = val.lineinfo.last }
|
||||
return r
|
||||
else return e end
|
||||
end
|
||||
|
||||
local function _table_field(lx) return table_field(lx) end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- table constructor, without enclosing braces; returns a full table object
|
||||
--------------------------------------------------------------------------------
|
||||
table_content = gg.list { _table_field,
|
||||
separators = { ",", ";" }, terminators = "}", builder = "Table" }
|
||||
|
||||
local function _table_content(lx) return table_content(lx) end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- complete table constructor including [{...}]
|
||||
--------------------------------------------------------------------------------
|
||||
table = gg.sequence{ "{", _table_content, "}", builder = fget(1) }
|
||||
|
||||
|
||||
295
lualibs/metalua/pprint.lua
Normal file
295
lualibs/metalua/pprint.lua
Normal file
@@ -0,0 +1,295 @@
|
||||
-------------------------------------------------------------------------------
|
||||
-- Copyright (c) 2006-2013 Fabien Fleutot and others.
|
||||
--
|
||||
-- All rights reserved.
|
||||
--
|
||||
-- This program and the accompanying materials are made available
|
||||
-- under the terms of the Eclipse Public License v1.0 which
|
||||
-- accompanies this distribution, and is available at
|
||||
-- http://www.eclipse.org/legal/epl-v10.html
|
||||
--
|
||||
-- This program and the accompanying materials are also made available
|
||||
-- under the terms of the MIT public license which accompanies this
|
||||
-- distribution, and is available at http://www.lua.org/license.html
|
||||
--
|
||||
-- Contributors:
|
||||
-- Fabien Fleutot - API and implementation
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
|
||||
----------------------------------------------------------------------
|
||||
----------------------------------------------------------------------
|
||||
--
|
||||
-- Lua objects pretty-printer
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
----------------------------------------------------------------------
|
||||
|
||||
local M = { }
|
||||
|
||||
M.DEFAULT_CFG = {
|
||||
hide_hash = false; -- Print the non-array part of tables?
|
||||
metalua_tag = true; -- Use Metalua's backtick syntax sugar?
|
||||
fix_indent = nil; -- If a number, number of indentation spaces;
|
||||
-- If false, indent to the previous brace.
|
||||
line_max = nil; -- If a number, tries to avoid making lines with
|
||||
-- more than this number of chars.
|
||||
initial_indent = 0; -- If a number, starts at this level of indentation
|
||||
keywords = { }; -- Set of keywords which must not use Lua's field
|
||||
-- shortcuts {["foo"]=...} -> {foo=...}
|
||||
}
|
||||
|
||||
local function valid_id(cfg, x)
|
||||
if type(x) ~= "string" then return false end
|
||||
if not x:match "^[a-zA-Z_][a-zA-Z0-9_]*$" then return false end
|
||||
if cfg.keywords and cfg.keywords[x] then return false end
|
||||
return true
|
||||
end
|
||||
|
||||
local __tostring_cache = setmetatable({ }, {__mode='k'})
|
||||
|
||||
-- Retrieve the string produced by `__tostring` metamethod if present,
|
||||
-- return `false` otherwise. Cached in `__tostring_cache`.
|
||||
local function __tostring(x)
|
||||
local the_string = __tostring_cache[x]
|
||||
if the_string~=nil then return the_string end
|
||||
local mt = getmetatable(x)
|
||||
if mt then
|
||||
local __tostring = mt.__tostring
|
||||
if __tostring then
|
||||
the_string = __tostring(x)
|
||||
__tostring_cache[x] = the_string
|
||||
return the_string
|
||||
end
|
||||
end
|
||||
if x~=nil then __tostring_cache[x] = false end -- nil is an illegal key
|
||||
return false
|
||||
end
|
||||
|
||||
local xlen -- mutually recursive with `xlen_type`
|
||||
|
||||
local xlen_cache = setmetatable({ }, {__mode='k'})
|
||||
|
||||
-- Helpers for the `xlen` function
|
||||
local xlen_type = {
|
||||
["nil"] = function ( ) return 3 end;
|
||||
number = function (x) return #tostring(x) end;
|
||||
boolean = function (x) return x and 4 or 5 end;
|
||||
string = function (x) return #string.format("%q",x) end;
|
||||
}
|
||||
|
||||
function xlen_type.table (adt, cfg, nested)
|
||||
local custom_string = __tostring(adt)
|
||||
if custom_string then return #custom_string end
|
||||
|
||||
-- Circular referenced objects are printed with the plain
|
||||
-- `tostring` function in nested positions.
|
||||
if nested [adt] then return #tostring(adt) end
|
||||
nested [adt] = true
|
||||
|
||||
local has_tag = cfg.metalua_tag and valid_id(cfg, adt.tag)
|
||||
local alen = #adt
|
||||
local has_arr = alen>0
|
||||
local has_hash = false
|
||||
local x = 0
|
||||
|
||||
if not cfg.hide_hash then
|
||||
-- first pass: count hash-part
|
||||
for k, v in pairs(adt) do
|
||||
if k=="tag" and has_tag then
|
||||
-- this is the tag -> do nothing!
|
||||
elseif type(k)=="number" and k<=alen and math.fmod(k,1)==0 and k>0 then
|
||||
-- array-part pair -> do nothing!
|
||||
else
|
||||
has_hash = true
|
||||
if valid_id(cfg, k) then x=x+#k
|
||||
else x = x + xlen (k, cfg, nested) + 2 end -- count surrounding brackets
|
||||
x = x + xlen (v, cfg, nested) + 5 -- count " = " and ", "
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for i = 1, alen do x = x + xlen (adt[i], nested) + 2 end -- count ", "
|
||||
|
||||
nested[adt] = false -- No more nested calls
|
||||
|
||||
if not (has_tag or has_arr or has_hash) then return 3 end
|
||||
if has_tag then x=x+#adt.tag+1 end
|
||||
if not (has_arr or has_hash) then return x end
|
||||
if not has_hash and alen==1 and type(adt[1])~="table" then
|
||||
return x-2 -- substract extraneous ", "
|
||||
end
|
||||
return x+2 -- count "{ " and " }", substract extraneous ", "
|
||||
end
|
||||
|
||||
|
||||
-- Compute the number of chars it would require to display the table
|
||||
-- on a single line. Helps to decide whether some carriage returns are
|
||||
-- required. Since the size of each sub-table is required many times,
|
||||
-- it's cached in [xlen_cache].
|
||||
xlen = function (x, cfg, nested)
|
||||
-- no need to compute length for 1-line prints
|
||||
if not cfg.line_max then return 0 end
|
||||
nested = nested or { }
|
||||
if x==nil then return #"nil" end
|
||||
local len = xlen_cache[x]
|
||||
if len then return len end
|
||||
local f = xlen_type[type(x)]
|
||||
if not f then return #tostring(x) end
|
||||
len = f (x, cfg, nested)
|
||||
xlen_cache[x] = len
|
||||
return len
|
||||
end
|
||||
|
||||
local function consider_newline(p, len)
|
||||
if not p.cfg.line_max then return end
|
||||
if p.current_offset + len <= p.cfg.line_max then return end
|
||||
if p.indent < p.current_offset then
|
||||
p:acc "\n"; p:acc ((" "):rep(p.indent))
|
||||
p.current_offset = p.indent
|
||||
end
|
||||
end
|
||||
|
||||
local acc_value
|
||||
|
||||
local acc_type = {
|
||||
["nil"] = function(p) p:acc("nil") end;
|
||||
number = function(p, adt) p:acc (tostring (adt)) end;
|
||||
string = function(p, adt) p:acc ((string.format ("%q", adt):gsub("\\\n", "\\n"))) end;
|
||||
boolean = function(p, adt) p:acc (adt and "true" or "false") end }
|
||||
|
||||
-- Indentation:
|
||||
-- * if `cfg.fix_indent` is set to a number:
|
||||
-- * add this number of space for each level of depth
|
||||
-- * return to the line as soon as it flushes things further left
|
||||
-- * if not, tabulate to one space after the opening brace.
|
||||
-- * as a result, it never saves right-space to return before first element
|
||||
|
||||
function acc_type.table(p, adt)
|
||||
if p.nested[adt] then p:acc(tostring(adt)); return end
|
||||
p.nested[adt] = true
|
||||
|
||||
local has_tag = p.cfg.metalua_tag and valid_id(p.cfg, adt.tag)
|
||||
local alen = #adt
|
||||
local has_arr = alen>0
|
||||
local has_hash = false
|
||||
|
||||
local previous_indent = p.indent
|
||||
|
||||
if has_tag then p:acc("`"); p:acc(adt.tag) end
|
||||
|
||||
local function indent(p)
|
||||
if not p.cfg.fix_indent then p.indent = p.current_offset
|
||||
else p.indent = p.indent + p.cfg.fix_indent end
|
||||
end
|
||||
|
||||
-- First pass: handle hash-part
|
||||
if not p.cfg.hide_hash then
|
||||
for k, v in pairs(adt) do
|
||||
|
||||
if has_tag and k=='tag' then -- pass the 'tag' field
|
||||
elseif type(k)=="number" and k<=alen and k>0 and math.fmod(k,1)==0 then
|
||||
-- pass array-part keys (consecutive ints less than `#adt`)
|
||||
else -- hash-part keys
|
||||
if has_hash then p:acc ", " else -- 1st hash-part pair ever found
|
||||
p:acc "{ "; indent(p)
|
||||
end
|
||||
|
||||
-- Determine whether a newline is required
|
||||
local is_id, expected_len=valid_id(p.cfg, k)
|
||||
if is_id then expected_len=#k+xlen(v, p.cfg, p.nested)+#" = , "
|
||||
else expected_len = xlen(k, p.cfg, p.nested)+xlen(v, p.cfg, p.nested)+#"[] = , " end
|
||||
consider_newline(p, expected_len)
|
||||
|
||||
-- Print the key
|
||||
if is_id then p:acc(k); p:acc " = " else
|
||||
p:acc "["; acc_value (p, k); p:acc "] = "
|
||||
end
|
||||
|
||||
acc_value (p, v) -- Print the value
|
||||
has_hash = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Now we know whether there's a hash-part, an array-part, and a tag.
|
||||
-- Tag and hash-part are already printed if they're present.
|
||||
if not has_tag and not has_hash and not has_arr then p:acc "{ }";
|
||||
elseif has_tag and not has_hash and not has_arr then -- nothing, tag already in acc
|
||||
else
|
||||
assert (has_hash or has_arr) -- special case { } already handled
|
||||
local no_brace = false
|
||||
if has_hash and has_arr then p:acc ", "
|
||||
elseif has_tag and not has_hash and alen==1 and type(adt[1])~="table" then
|
||||
-- No brace required; don't print "{", remember not to print "}"
|
||||
p:acc (" "); acc_value (p, adt[1]) -- indent= indent+(cfg.fix_indent or 0))
|
||||
no_brace = true
|
||||
elseif not has_hash then
|
||||
-- Braces required, but not opened by hash-part handler yet
|
||||
p:acc "{ "; indent(p)
|
||||
end
|
||||
|
||||
-- 2nd pass: array-part
|
||||
if not no_brace and has_arr then
|
||||
local expected_len = xlen(adt[1], p.cfg, p.nested)
|
||||
consider_newline(p, expected_len)
|
||||
acc_value(p, adt[1]) -- indent+(cfg.fix_indent or 0)
|
||||
for i=2, alen do
|
||||
p:acc ", ";
|
||||
consider_newline(p, xlen(adt[i], p.cfg, p.nested))
|
||||
acc_value (p, adt[i]) --indent+(cfg.fix_indent or 0)
|
||||
end
|
||||
end
|
||||
if not no_brace then p:acc " }" end
|
||||
end
|
||||
p.nested[adt] = false -- No more nested calls
|
||||
p.indent = previous_indent
|
||||
end
|
||||
|
||||
|
||||
function acc_value(p, v)
|
||||
local custom_string = __tostring(v)
|
||||
if custom_string then p:acc(custom_string) else
|
||||
local f = acc_type[type(v)]
|
||||
if f then f(p, v) else p:acc(tostring(v)) end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- FIXME: new_indent seems to be always nil?!s detection
|
||||
-- FIXME: accumulator function should be configurable,
|
||||
-- so that print() doesn't need to bufferize the whole string
|
||||
-- before starting to print.
|
||||
function M.tostring(t, cfg)
|
||||
|
||||
cfg = cfg or M.DEFAULT_CFG or { }
|
||||
|
||||
local p = {
|
||||
cfg = cfg;
|
||||
indent = 0;
|
||||
current_offset = cfg.initial_indent or 0;
|
||||
buffer = { };
|
||||
nested = { };
|
||||
acc = function(self, str)
|
||||
table.insert(self.buffer, str)
|
||||
self.current_offset = self.current_offset + #str
|
||||
end;
|
||||
}
|
||||
acc_value(p, t)
|
||||
return table.concat(p.buffer)
|
||||
end
|
||||
|
||||
function M.print(...) return print(M.tostring(...)) end
|
||||
function M.sprintf(fmt, ...)
|
||||
local args={...}
|
||||
for i, v in pairs(args) do
|
||||
local t=type(v)
|
||||
if t=='table' then args[i]=M.tostring(v)
|
||||
elseif t=='nil' then args[i]='nil' end
|
||||
end
|
||||
return string.format(fmt, unpack(args))
|
||||
end
|
||||
|
||||
function M.printf(...) print(M.sprintf(...)) end
|
||||
|
||||
return M
|
||||
@@ -1,45 +1,65 @@
|
||||
--
|
||||
-- MobDebug 0.55
|
||||
-- Copyright 2011-13 Paul Kulchenko
|
||||
-- MobDebug 0.60
|
||||
-- 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.55,
|
||||
_VERSION = 0.60,
|
||||
_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
|
||||
local jit = rawget(genv, "jit")
|
||||
local MOAICoroutine = rawget(genv, "MOAICoroutine")
|
||||
|
||||
-- ngx_lua debugging requires a special handling as its coroutine.*
|
||||
-- methods use a different mechanism that doesn't allow resume calls
|
||||
-- from debug hook handlers.
|
||||
-- Instead, the "original" coroutine.* methods are used.
|
||||
-- `rawget` needs to be used to protect against `strict` checks, but
|
||||
-- ngx_lua hides those in a metatable, so need to use that.
|
||||
local metagindex = getmetatable(genv) and getmetatable(genv).__index
|
||||
local ngx = type(metagindex) == "table" and metagindex.rawget and metagindex:rawget("ngx") or nil
|
||||
local corocreate = ngx and coroutine._create or coroutine.create
|
||||
local cororesume = ngx and coroutine._resume or coroutine.resume
|
||||
local coroyield = ngx and coroutine._yield or coroutine.yield
|
||||
local corostatus = ngx and coroutine._status or coroutine.status
|
||||
|
||||
if not setfenv then -- Lua 5.2
|
||||
-- based on http://lua-users.org/lists/lua-l/2010-06/msg00314.html
|
||||
-- this assumes f is a function
|
||||
@@ -98,7 +118,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)
|
||||
@@ -106,7 +126,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}
|
||||
@@ -116,7 +136,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
|
||||
@@ -138,13 +158,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)
|
||||
@@ -200,7 +220,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
|
||||
@@ -211,8 +231,26 @@ 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 }
|
||||
@@ -220,6 +258,8 @@ end)() ---- end of Serpent module
|
||||
|
||||
mobdebug.line = serpent.line
|
||||
mobdebug.dump = serpent.dump
|
||||
mobdebug.linemap = nil
|
||||
mobdebug.loadstring = loadstring
|
||||
|
||||
local function removebasedir(path, basedir)
|
||||
if iscasepreserving then
|
||||
@@ -255,6 +295,7 @@ local function stack(start)
|
||||
end
|
||||
|
||||
local stack = {}
|
||||
local linemap = mobdebug.linemap
|
||||
for i = (start or 0), 100 do
|
||||
local source = debug.getinfo(i, "Snl")
|
||||
if not source then break end
|
||||
@@ -266,8 +307,10 @@ local function stack(start)
|
||||
end
|
||||
|
||||
table.insert(stack, { -- remove basedir from source
|
||||
{source.name, removebasedir(src, basedir), source.linedefined,
|
||||
source.currentline, source.what, source.namewhat, source.short_src},
|
||||
{source.name, removebasedir(src, basedir),
|
||||
linemap and linemap(source.linedefined, source.source) or source.linedefined,
|
||||
linemap and linemap(source.currentline, source.source) or source.currentline,
|
||||
source.what, source.namewhat, source.short_src},
|
||||
vars(i+1)})
|
||||
if source.what == 'main' then break end
|
||||
end
|
||||
@@ -404,6 +447,46 @@ local function is_pending(peer)
|
||||
return buf
|
||||
end
|
||||
|
||||
local function readnext(peer, num)
|
||||
peer:settimeout(0) -- non-blocking
|
||||
local res, err, partial = peer:receive(num)
|
||||
peer:settimeout() -- back to blocking
|
||||
return res or partial or '', err
|
||||
end
|
||||
|
||||
local function handle_breakpoint(peer)
|
||||
-- check if the buffer has the beginning of SETB/DELB command;
|
||||
-- this is to avoid reading the entire line for commands that
|
||||
-- don't need to be handled here.
|
||||
if not buf or not (buf:sub(1,1) == 'S' or buf:sub(1,1) == 'D') then return end
|
||||
|
||||
-- check second character to avoid reading STEP or other S* and D* commands
|
||||
if #buf == 1 then buf = buf .. readnext(peer, 1) end
|
||||
if buf:sub(2,2) ~= 'E' then return end
|
||||
|
||||
-- need to read few more characters
|
||||
buf = buf .. readnext(peer, 5-#buf)
|
||||
if buf ~= 'SETB ' and buf ~= 'DELB ' then return end
|
||||
|
||||
local res, _, partial = peer:receive() -- get the rest of the line; blocking
|
||||
if not res then
|
||||
if partial then buf = buf .. partial end
|
||||
return
|
||||
end
|
||||
|
||||
local _, _, cmd, file, line = (buf..res):find("^([A-Z]+)%s+(.-)%s+(%d+)%s*$")
|
||||
if cmd == 'SETB' then set_breakpoint(file, tonumber(line))
|
||||
elseif cmd == 'DELB' then remove_breakpoint(file, tonumber(line))
|
||||
else
|
||||
-- this looks like a breakpoint command, but something went wrong;
|
||||
-- return here to let the "normal" processing to handle,
|
||||
-- although this is likely to not go well.
|
||||
return
|
||||
end
|
||||
|
||||
buf = nil
|
||||
end
|
||||
|
||||
local function debug_hook(event, line)
|
||||
-- (1) LuaJIT needs special treatment. Because debug_hook is set for
|
||||
-- *all* coroutines, and not just the one being debugged as in regular Lua
|
||||
@@ -439,6 +522,12 @@ local function debug_hook(event, line)
|
||||
elseif event == "return" or event == "tail return" then
|
||||
stack_level = stack_level - 1
|
||||
elseif event == "line" then
|
||||
if mobdebug.linemap then
|
||||
local ok, mappedline = pcall(mobdebug.linemap, line, debug.getinfo(2, "S").source)
|
||||
if ok then line = mappedline end
|
||||
if not line then return end
|
||||
end
|
||||
|
||||
-- may need to fall through because of the following:
|
||||
-- (1) step_into
|
||||
-- (2) step_over and stack_level <= step_level (need stack_level)
|
||||
@@ -484,14 +573,19 @@ local function debug_hook(event, line)
|
||||
-- set on foo.lua will not work if not converted to the same case.
|
||||
if iscasepreserving then file = string.lower(file) end
|
||||
if file:find("%./") == 1 then file = file:sub(3)
|
||||
else file = file:gsub('^'..q(basedir), '') end
|
||||
else file = file:gsub("^"..q(basedir), "") end
|
||||
-- some file systems allow newlines in file names; remove these.
|
||||
file = file:gsub("\n", ' ')
|
||||
else
|
||||
-- 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 mobdebug.line(file) or file
|
||||
if file:find("[\r\n]") then
|
||||
file = mobdebug.line(file)
|
||||
else
|
||||
if iscasepreserving then file = string.lower(file) end
|
||||
file = file:gsub("\\", "/"):gsub(file:find("^%./") and "^%./" or "^"..q(basedir), "")
|
||||
end
|
||||
end
|
||||
|
||||
-- set to true if we got here; this only needs to be done once per
|
||||
@@ -500,6 +594,8 @@ local function debug_hook(event, line)
|
||||
lastfile = file
|
||||
end
|
||||
|
||||
if is_pending(server) then handle_breakpoint(server) end
|
||||
|
||||
local vars, status, res
|
||||
if (watchescnt > 0) then
|
||||
vars = capture_vars()
|
||||
@@ -507,7 +603,7 @@ local function debug_hook(event, line)
|
||||
setfenv(value, vars)
|
||||
local ok, fired = pcall(value)
|
||||
if ok and fired then
|
||||
status, res = coroutine.resume(coro_debugger, events.WATCH, vars, file, line, index)
|
||||
status, res = cororesume(coro_debugger, events.WATCH, vars, file, line, index)
|
||||
break -- any one watch is enough; don't check multiple times
|
||||
end
|
||||
end
|
||||
@@ -527,7 +623,7 @@ local function debug_hook(event, line)
|
||||
vars = vars or capture_vars()
|
||||
step_into = false
|
||||
step_over = false
|
||||
status, res = coroutine.resume(coro_debugger, events.BREAK, vars, file, line)
|
||||
status, res = cororesume(coro_debugger, events.BREAK, vars, file, line)
|
||||
end
|
||||
|
||||
-- handle 'stack' command that provides stack() information to the debugger
|
||||
@@ -536,15 +632,15 @@ local function debug_hook(event, line)
|
||||
-- resume with the stack trace and variables
|
||||
if vars then restore_vars(vars) end -- restore vars so they are reflected in stack values
|
||||
-- this may fail if __tostring method fails at run-time
|
||||
local ok, snapshot = pcall(stack, 4)
|
||||
status, res = coroutine.resume(coro_debugger, ok and events.STACK or events.BREAK, snapshot, file, line)
|
||||
local ok, snapshot = pcall(stack, ngx and 5 or 4)
|
||||
status, res = cororesume(coro_debugger, ok and events.STACK or events.BREAK, snapshot, file, line)
|
||||
end
|
||||
end
|
||||
|
||||
-- need to recheck once more as resume after 'stack' command may
|
||||
-- return something else (for example, 'exit'), which needs to be handled
|
||||
if status and res and res ~= 'stack' then
|
||||
if abort == nil and res == "exit" then os.exit(1); 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
|
||||
@@ -574,6 +670,30 @@ local function stringify_results(status, ...)
|
||||
return pcall(mobdebug.dump, t, {sparse = false})
|
||||
end
|
||||
|
||||
local function isrunning()
|
||||
return coro_debugger and corostatus(coro_debugger) == 'suspended'
|
||||
end
|
||||
|
||||
-- this is a function that removes all hooks and closes the socket to
|
||||
-- report back to the controller that the debugging is done.
|
||||
-- the script that called `done` can still continue.
|
||||
local function done()
|
||||
if not (isrunning() and server) then return end
|
||||
|
||||
if not jit then
|
||||
for co, debugged in pairs(coroutines) do
|
||||
if debugged then debug.sethook(co) end
|
||||
end
|
||||
end
|
||||
|
||||
debug.sethook()
|
||||
server:close()
|
||||
|
||||
coro_debugger = nil -- to make sure isrunning() returns `false`
|
||||
seen_hook = nil -- to make sure that the next start() call works
|
||||
abort = nil -- to make sure that callback calls use proper "abort" value
|
||||
end
|
||||
|
||||
local function debugger_loop(sev, svars, sfile, sline)
|
||||
local command
|
||||
local app, osname
|
||||
@@ -638,8 +758,8 @@ local function debugger_loop(sev, svars, sfile, sline)
|
||||
end
|
||||
elseif command == "EXEC" then
|
||||
local _, _, chunk = string.find(line, "^[A-Z]+%s+(.+)$")
|
||||
if chunk then
|
||||
local func, res = loadstring(chunk)
|
||||
if chunk then
|
||||
local func, res = mobdebug.loadstring(chunk)
|
||||
local status
|
||||
if func then
|
||||
setfenv(func, eval_env)
|
||||
@@ -675,16 +795,16 @@ local function debugger_loop(sev, svars, sfile, sline)
|
||||
|
||||
if size == 0 and name == '-' then -- RELOAD the current script being debugged
|
||||
server:send("200 OK 0\n")
|
||||
coroutine.yield("load")
|
||||
coroyield("load")
|
||||
else
|
||||
-- receiving 0 bytes blocks (at least in luasocket 2.0.2), so skip reading
|
||||
local chunk = size == 0 and "" or server:receive(size)
|
||||
if chunk then -- LOAD a new script for debugging
|
||||
local func, res = loadstring(chunk, "@"..name)
|
||||
local func, res = mobdebug.loadstring(chunk, "@"..name)
|
||||
if func then
|
||||
server:send("200 OK 0\n")
|
||||
debugee = func
|
||||
coroutine.yield("load")
|
||||
coroyield("load")
|
||||
else
|
||||
server:send("401 Error in Expression " .. #res .. "\n")
|
||||
server:send(res)
|
||||
@@ -696,13 +816,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
|
||||
local func, res = loadstring("return(" .. exp .. ")")
|
||||
if exp then
|
||||
local func, res = mobdebug.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)
|
||||
@@ -723,7 +843,7 @@ local function debugger_loop(sev, svars, sfile, sline)
|
||||
elseif command == "RUN" then
|
||||
server:send("200 OK\n")
|
||||
|
||||
local ev, vars, file, line, idx_watch = coroutine.yield()
|
||||
local ev, vars, file, line, idx_watch = coroyield()
|
||||
eval_env = vars
|
||||
if ev == events.BREAK then
|
||||
server:send("202 Paused " .. file .. " " .. line .. "\n")
|
||||
@@ -739,7 +859,7 @@ local function debugger_loop(sev, svars, sfile, sline)
|
||||
server:send("200 OK\n")
|
||||
step_into = true
|
||||
|
||||
local ev, vars, file, line, idx_watch = coroutine.yield()
|
||||
local ev, vars, file, line, idx_watch = coroyield()
|
||||
eval_env = vars
|
||||
if ev == events.BREAK then
|
||||
server:send("202 Paused " .. file .. " " .. line .. "\n")
|
||||
@@ -754,13 +874,13 @@ 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
|
||||
|
||||
local ev, vars, file, line, idx_watch = coroutine.yield()
|
||||
local ev, vars, file, line, idx_watch = coroyield()
|
||||
eval_env = vars
|
||||
if ev == events.BREAK then
|
||||
server:send("202 Paused " .. file .. " " .. line .. "\n")
|
||||
@@ -784,6 +904,10 @@ local function debugger_loop(sev, svars, sfile, sline)
|
||||
end
|
||||
elseif command == "SUSPEND" then
|
||||
-- do nothing; it already fulfilled its role
|
||||
elseif command == "DONE" then
|
||||
server:send("200 OK\n")
|
||||
done()
|
||||
return -- done with all the debugging
|
||||
elseif command == "STACK" then
|
||||
-- first check if we can execute the stack command
|
||||
-- as it requires yielding back to debug_hook it cannot be executed
|
||||
@@ -791,7 +915,7 @@ local function debugger_loop(sev, svars, sfile, sline)
|
||||
-- in this case we simply return an empty result
|
||||
local vars, ev = {}
|
||||
if seen_hook then
|
||||
ev, vars = coroutine.yield("stack")
|
||||
ev, vars = coroyield("stack")
|
||||
end
|
||||
if ev and ev ~= events.STACK then
|
||||
server:send("401 Error in Execution " .. #vars .. "\n")
|
||||
@@ -831,7 +955,7 @@ local function debugger_loop(sev, svars, sfile, sline)
|
||||
end
|
||||
elseif command == "EXIT" then
|
||||
server:send("200 OK\n")
|
||||
coroutine.yield("exit")
|
||||
coroyield("exit")
|
||||
else
|
||||
server:send("400 Bad Request\n")
|
||||
end
|
||||
@@ -842,10 +966,6 @@ local function connect(controller_host, controller_port)
|
||||
return (socket.connect4 or socket.connect)(controller_host, controller_port)
|
||||
end
|
||||
|
||||
local function isrunning()
|
||||
return coro_debugger and coroutine.status(coro_debugger) == 'suspended'
|
||||
end
|
||||
|
||||
local lasthost, lastport
|
||||
|
||||
-- Starts a debug session by connecting to a controller
|
||||
@@ -891,7 +1011,7 @@ local function start(controller_host, controller_port)
|
||||
return (dtraceback(...):gsub("(stack traceback:\n)[^\n]*\n", "%1"))
|
||||
end
|
||||
end
|
||||
coro_debugger = coroutine.create(debugger_loop)
|
||||
coro_debugger = corocreate(debugger_loop)
|
||||
debug.sethook(debug_hook, "lcr")
|
||||
seen_hook = nil -- reset in case the last start() call was refused
|
||||
step_into = true -- start with step command
|
||||
@@ -924,16 +1044,16 @@ local function controller(controller_host, controller_port, scratchpad)
|
||||
end
|
||||
|
||||
seen_hook = true -- allow to accept all commands
|
||||
coro_debugger = coroutine.create(debugger_loop)
|
||||
coro_debugger = corocreate(debugger_loop)
|
||||
|
||||
while true do
|
||||
step_into = true -- start with step command
|
||||
abort = false -- reset abort flag from the previous loop
|
||||
if scratchpad then checkcount = mobdebug.checkcount end -- force suspend right away
|
||||
|
||||
coro_debugee = coroutine.create(debugee)
|
||||
coro_debugee = corocreate(debugee)
|
||||
debug.sethook(coro_debugee, debug_hook, "lcr")
|
||||
local status, err = coroutine.resume(coro_debugee)
|
||||
local status, err = cororesume(coro_debugee)
|
||||
|
||||
-- was there an error or is the script done?
|
||||
-- 'abort' state is allowed here; ignore it
|
||||
@@ -955,7 +1075,7 @@ local function controller(controller_host, controller_port, scratchpad)
|
||||
-- variable from console, but they will be reset anyway.
|
||||
-- This functionality is used when scratchpad is paused to
|
||||
-- gain access to remote console to modify global variables.
|
||||
local status, err = coroutine.resume(coro_debugger, events.RESTART, capture_vars(2))
|
||||
local status, err = cororesume(coro_debugger, events.RESTART, capture_vars(2))
|
||||
if not status or status and err == "exit" then break end
|
||||
end
|
||||
end
|
||||
@@ -1013,14 +1133,14 @@ local function off()
|
||||
-- if not, turn the debugging off
|
||||
if jit then
|
||||
local remove = true
|
||||
for co, debugged in pairs(coroutines) do
|
||||
for _, debugged in pairs(coroutines) do
|
||||
if debugged then remove = false; break end
|
||||
end
|
||||
if remove then debug.sethook() end
|
||||
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
|
||||
@@ -1033,7 +1153,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+)")
|
||||
@@ -1063,18 +1183,25 @@ 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
|
||||
if done then break end
|
||||
end
|
||||
elseif command == "setb" then
|
||||
elseif command == "done" then
|
||||
client:send(string.upper(command) .. "\n")
|
||||
if client:receive() ~= "200 OK" then
|
||||
print("Unknown error")
|
||||
os.exit(1, true)
|
||||
return nil, nil, "Debugger error: unexpected response after 'done'"
|
||||
end
|
||||
elseif command == "setb" or command == "asetb" then
|
||||
_, _, _, file, line = string.find(params, "^([a-z]+)%s+(.-)%s+(%d+)%s*$")
|
||||
if file and line then
|
||||
-- if this is a file name, and not a file source
|
||||
@@ -1083,7 +1210,7 @@ local function handle(params, client, options)
|
||||
file = removebasedir(file, basedir)
|
||||
end
|
||||
client:send("SETB " .. file .. " " .. line .. "\n")
|
||||
if client:receive() == "200 OK" then
|
||||
if command == "asetb" or client:receive() == "200 OK" then
|
||||
set_breakpoint(file, line)
|
||||
else
|
||||
print("Error: breakpoint not inserted")
|
||||
@@ -1112,7 +1239,7 @@ local function handle(params, client, options)
|
||||
else
|
||||
print("Invalid command")
|
||||
end
|
||||
elseif command == "delb" then
|
||||
elseif command == "delb" or command == "adelb" then
|
||||
_, _, _, file, line = string.find(params, "^([a-z]+)%s+(.-)%s+(%d+)%s*$")
|
||||
if file and line then
|
||||
-- if this is a file name, and not a file source
|
||||
@@ -1121,7 +1248,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 command == "adelb" or client:receive() == "200 OK" then
|
||||
remove_breakpoint(file, line)
|
||||
else
|
||||
print("Error: breakpoint not removed")
|
||||
@@ -1144,7 +1271,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")
|
||||
@@ -1155,17 +1282,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
|
||||
@@ -1265,7 +1392,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
|
||||
@@ -1355,7 +1482,8 @@ local function handle(params, client, options)
|
||||
print("stack -- reports stack trace")
|
||||
print("output stdout <d|c|r> -- capture and redirect io stream (default|copy|redirect)")
|
||||
print("basedir [<path>] -- sets the base path of the remote application, or shows the current one")
|
||||
print("exit -- exits debugger")
|
||||
print("done -- stops the debugger and continues application execution")
|
||||
print("exit -- exits debugger and the application")
|
||||
else
|
||||
local _, _, spaces = string.find(params, "^(%s*)$")
|
||||
if not spaces then
|
||||
@@ -1408,7 +1536,7 @@ local function coro()
|
||||
cocreate = cocreate or coroutine.create
|
||||
coroutine.create = function(f, ...)
|
||||
return cocreate(function(...)
|
||||
require("mobdebug").on()
|
||||
mobdebug.on()
|
||||
return f(...)
|
||||
end, ...)
|
||||
end
|
||||
@@ -1427,7 +1555,7 @@ local function moai()
|
||||
local patched = mt.run
|
||||
mt.run = function(self, f, ...)
|
||||
return patched(self, function(...)
|
||||
require("mobdebug").on()
|
||||
mobdebug.on()
|
||||
return f(...)
|
||||
end, ...)
|
||||
end
|
||||
@@ -1435,26 +1563,6 @@ local function moai()
|
||||
end
|
||||
end
|
||||
|
||||
-- this is a function that removes all hooks and closes the socket to
|
||||
-- report back to the controller that the debugging is done.
|
||||
-- the script that called `done` can still continue.
|
||||
local function done()
|
||||
if not (isrunning() and server) then return end
|
||||
|
||||
if not jit then
|
||||
for co, debugged in pairs(coroutines) do
|
||||
if debugged then debug.sethook(co) end
|
||||
end
|
||||
end
|
||||
|
||||
debug.sethook()
|
||||
server:close()
|
||||
|
||||
coro_debugger = nil -- to make sure isrunning() returns `false`
|
||||
seen_hook = nil -- to make sure that the next start() call works
|
||||
abort = nil -- to make sure that callback calls use proper "abort" value
|
||||
end
|
||||
|
||||
-- make public functions available
|
||||
mobdebug.setbreakpoint = set_breakpoint
|
||||
mobdebug.removebreakpoint = remove_breakpoint
|
||||
@@ -1469,6 +1577,7 @@ mobdebug.off = off
|
||||
mobdebug.moai = moai
|
||||
mobdebug.coro = coro
|
||||
mobdebug.done = done
|
||||
mobdebug.pause = function() step_into = true end
|
||||
mobdebug.yield = nil -- callback
|
||||
|
||||
-- this is needed to make "require 'modebug'" to work when mobdebug
|
||||
|
||||
239
lualibs/sha2.lua
Normal file
239
lualibs/sha2.lua
Normal 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,
|
||||
}
|
||||
@@ -11,6 +11,8 @@ local P = {
|
||||
-- abort further processing.
|
||||
-- For `onEditorPreSave` event it means that file saving will be aborted.
|
||||
-- For `onEditorKeyDown` event it means that the key will be "eaten".
|
||||
-- For `onEditorAction` event it means that the action will not be executed.
|
||||
-- For `onFiletreeActivate` event it means that no further processing is done.
|
||||
-- For `onEditorCharAdded` event it means that no further processing is done
|
||||
-- (but the character is still added to the editor).
|
||||
|
||||
@@ -24,8 +26,15 @@ local events = {
|
||||
onEditorSave = function(self, editor) end,
|
||||
onEditorFocusLost = function(self, editor) end,
|
||||
onEditorFocusSet = function(self, editor) end,
|
||||
onEditorAction = function(self, editor, event) end, -- return false
|
||||
onEditorKeyDown = function(self, editor, event) end, -- return false
|
||||
onEditorCharAdded = function(self, editor, event) end, -- return false
|
||||
onEditorUserlistSelection = function(self, editor, event) end, -- return false
|
||||
onEditorUpdateUI = function(self, editor, event) end, -- return false
|
||||
onEditorPainted = function(self, editor, event) end, -- return false
|
||||
onFiletreeActivate = function(self, tree, event, item) end, -- return false
|
||||
onFiletreeLDown = function(self, tree, event, item) end,
|
||||
onFiletreeRDown = function(self, tree, event, item) end,
|
||||
onMenuEditor = function(self, menu, editor, event) end,
|
||||
onMenuEditorTab = function(self, menu, notebook, event, index) end,
|
||||
onMenuFiletree = function(self, menu, tree, event) end,
|
||||
@@ -34,6 +43,7 @@ local events = {
|
||||
onProjectClose = function(self, project) end,
|
||||
onInterpreterLoad = function(self, interpreter) end,
|
||||
onInterpreterClose = function(self, interpreter) end,
|
||||
onIdle = function(self, event) end,
|
||||
onIdleOnce = function(self, event) end,
|
||||
onAppFocusLost = function(self, app) end,
|
||||
onAppFocusSet = function(self, app) end,
|
||||
|
||||
10
spec/cg.lua
10
spec/cg.lua
@@ -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 = "%.",
|
||||
sep = ".",
|
||||
linecomment = "//",
|
||||
|
||||
isfncall = function(str)
|
||||
return string.find(str, funccall .. "%(")
|
||||
end,
|
||||
|
||||
isfndef = function(str)
|
||||
local l
|
||||
|
||||
@@ -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 = "%.",
|
||||
sep = ".",
|
||||
linecomment = "//",
|
||||
|
||||
isfncall = function(str)
|
||||
return string.find(str, funccall .. "%(")
|
||||
end,
|
||||
|
||||
isfndef = function(str)
|
||||
local l
|
||||
@@ -83,7 +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
|
||||
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
|
||||
@@ -152,7 +158,7 @@ return {
|
||||
imageAtomicAdd imageAtomicMin imageAtomicMax
|
||||
imageAtomicIncWrap imageAtomicDecWrap imageAtomicAnd
|
||||
imageAtomicOr imageAtomixXor imageAtomicExchange
|
||||
imageCompSwap
|
||||
imageAtomicCompSwap imageSize
|
||||
|
||||
memoryBarrier groupMemoryBarrier memoryBarrierAtomicCounter memoryBarrierShared memoryBarrierBuffer memoryBarrierImage
|
||||
|
||||
|
||||
@@ -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","usf",},
|
||||
lexer = wxstc.wxSTC_LEX_CPP,
|
||||
apitype = "hlsl",
|
||||
sep = "%.",
|
||||
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
|
||||
|
||||
77
spec/lua.lua
77
spec/lua.lua
@@ -4,10 +4,10 @@
|
||||
local funcdef = "([A-Za-z_][A-Za-z0-9_%.%:]*)%s*"
|
||||
local funccall = "([A-Za-z_][A-Za-z0-9_]*)%s*"
|
||||
local decindent = {
|
||||
['else'] = true, ['elseif'] = true, ['end'] = true}
|
||||
['else'] = true, ['elseif'] = true, ['until'] = true, ['end'] = true}
|
||||
local incindent = {
|
||||
['else'] = true, ['elseif'] = true, ['for'] = true, ['do'] = true,
|
||||
['if'] = true, ['repeat'] = true, ['until'] = true, ['while'] = true}
|
||||
['if'] = true, ['repeat'] = true, ['while'] = true}
|
||||
local function isfndef(str)
|
||||
local l
|
||||
local s,e,cap,par = string.find(str, "function%s+" .. funcdef .. "(%(.-%))")
|
||||
@@ -26,40 +26,65 @@ local function isfndef(str)
|
||||
return s,e,cap,l
|
||||
end
|
||||
|
||||
local q = EscapeMagic
|
||||
|
||||
return {
|
||||
exts = {"lua", "rockspec", "wlua"},
|
||||
lexer = wxstc.wxSTC_LEX_LUA,
|
||||
apitype = "lua",
|
||||
linecomment = "--",
|
||||
sep = "%.:",
|
||||
sep = ".:",
|
||||
isfncall = function(str)
|
||||
return string.find(str, funccall .. "[%({'\"]")
|
||||
end,
|
||||
isfndef = isfndef,
|
||||
isdecindent = function(str)
|
||||
str = str:gsub('%-%-%[=*%[.*%]=*%]',''):gsub('%-%-.*','')
|
||||
-- this handles three different cases:
|
||||
local term = str:match("^%s*(%w+)%s*$")
|
||||
-- (1) 'end', 'elseif', 'else'
|
||||
local term = (str:match("^%s*(%w+)%s*$")
|
||||
or str:match("^%s*(elseif)[%s%(]")
|
||||
or str:match("^%s*(until)[%s%(]")
|
||||
or str:match("^%s*(else)%f[%W]")
|
||||
)
|
||||
-- (1) 'end', 'elseif', 'else', 'until'
|
||||
local match = term and decindent[term]
|
||||
-- (2) 'end)' and 'end}'
|
||||
if not term then term, match = str:match("^%s*(end)%s*([%)%}]+)%s*[,;]?") end
|
||||
-- (2) 'end)', 'end}', 'end,', and 'end;'
|
||||
if not term then term, match = str:match("^%s*(end)%s*([%)%}]*)%s*[,;]?") end
|
||||
-- endFoo could be captured as well; filter it out
|
||||
if term and str:match("^%s*(end)%w") then term = nil end
|
||||
-- (3) '},', '};', '),' and ');'
|
||||
if not term then match = str:match("^%s*[%)%}]+%s*[,;]?%s*$") end
|
||||
|
||||
return match and 1 or 0, match and term and 1 or 0
|
||||
end,
|
||||
isincindent = function(str)
|
||||
str = (str:gsub('%-%-%[=*%[.*%]=*%]','')
|
||||
:gsub("'.-\\'","'"):gsub("'.-'","")
|
||||
:gsub('".-\\"','"'):gsub('".-"','')
|
||||
:gsub('%-%-.*','') -- strip comments after strings are processed
|
||||
:gsub("%b()","()") -- remove all function calls
|
||||
)
|
||||
local term = str:match("^%s*(%w+)%W*")
|
||||
term = term and incindent[term] and 1 or 0
|
||||
str = str:gsub("'.-'",""):gsub('".-"','')
|
||||
local terminc = term and incindent[term] and 1 or 0
|
||||
-- fix 'if' not terminated with 'then'
|
||||
-- or 'then' not started with 'if'
|
||||
if (term == 'if' or term == 'elseif') and not str:match("%f[%w]then%f[%W]")
|
||||
or (term == 'for') and not str:match("%S%s+do%f[%W]")
|
||||
or (term == 'while') and not str:match("%f[%w]do%f[%W]") then
|
||||
terminc = 0
|
||||
elseif not (term == 'if' or term == 'elseif') and str:match("%f[%w]then%f[%W]")
|
||||
or not (term == 'for') and str:match("%S%s+do%f[%W]")
|
||||
or not (term == 'while') and str:match("%f[%w]do%f[%W]") then
|
||||
terminc = 1
|
||||
end
|
||||
local _, opened = str:gsub("([%{%(])", "%1")
|
||||
local _, closed = str:gsub("([%}%)])", "%1")
|
||||
local func = (isfndef(str) or str:match("%W+function%s*%(")) and 1 or 0
|
||||
-- ended should only be used to negate term and func effects
|
||||
local anon = str:match("%W+function%s*%(.+%Wend%W")
|
||||
local ended = (term + func > 0) and (str:match("%W+end%s*$") or anon) and 1 or 0
|
||||
local ended = (terminc + func > 0) and (str:match("%W+end%s*$") or anon) and 1 or 0
|
||||
|
||||
return opened - closed + func + term - ended
|
||||
return opened - closed + func + terminc - ended
|
||||
end,
|
||||
markvars = function(code, pos, vars)
|
||||
local PARSE = require 'lua_parser_loose'
|
||||
@@ -92,7 +117,7 @@ return {
|
||||
local line = editor:GetCurrentLine()-1
|
||||
local maxlines = 48 -- scan up to this many lines back
|
||||
|
||||
local scopestart = {"if","do","while","function", "local%s+function", "for", "else", "elseif"}
|
||||
local scopestart = {"if", "do", "while", "function", "local%s+function", "for", "else", "elseif"}
|
||||
local scopeend = {"end"}
|
||||
local iscomment = editor.spec.iscomment
|
||||
|
||||
@@ -107,16 +132,16 @@ return {
|
||||
|
||||
if (not iscomment[s]) then
|
||||
local tx = editor:GetLine(line)
|
||||
local leftscope
|
||||
local sstart, send
|
||||
|
||||
for i,v in ipairs(scopestart) do
|
||||
if (tx:match("^%s*"..v)) then
|
||||
leftscope = true
|
||||
end
|
||||
for _, v in ipairs(scopestart) do
|
||||
if (tx:match("^%s*"..v.."%f[^%w]")) then sstart = true end
|
||||
end
|
||||
if (leftscope) then
|
||||
break
|
||||
for _, v in ipairs(scopeend) do
|
||||
if (tx:match("%f[%w]"..v.."%s*$")) then send = true end
|
||||
end
|
||||
-- if the scope starts, but doesn't end on one line, stop searching
|
||||
if sstart and not send then break end
|
||||
end
|
||||
line = line -1
|
||||
end
|
||||
@@ -129,8 +154,9 @@ return {
|
||||
local tx = editor:GetLine(line) --= string
|
||||
|
||||
-- check for assignments
|
||||
local varname = "([%w_][%w_%.]*)"
|
||||
local identifier = "([%w_][%w_%.:%s]*)"
|
||||
local sep = editor.spec.sep
|
||||
local varname = "([%w_][%w_"..q(sep:sub(1,1)).."]*)"
|
||||
local identifier = "([%w_][%w_"..q(sep).."%s]*)"
|
||||
|
||||
-- special hint
|
||||
local typ,var = tx:match("%s*%-%-=%s*"..varname.."%s+"..identifier)
|
||||
@@ -164,13 +190,12 @@ return {
|
||||
and (not typ:match('^'..identifier..'$') -- 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
|
||||
|
||||
if (var and typ) then
|
||||
class,func = typ:match(varname.."[%.:]"..varname)
|
||||
class,func = typ:match(varname.."["..q(sep).."]"..varname)
|
||||
if (assigns[typ]) then
|
||||
assigns[var] = assigns[typ]
|
||||
elseif (func) then
|
||||
@@ -228,8 +253,7 @@ return {
|
||||
keywords = {
|
||||
[[and break do else elseif end for function goto if in local not or repeat return then until while]],
|
||||
|
||||
[[_G _VERSION _ENV false io.stderr io.stdin io.stdout nil math.huge math.pi package.config
|
||||
package.cpath package.loaded package.loaders package.path package.preload package.searchers self true]],
|
||||
[[_G _VERSION _ENV false io.stderr io.stdin io.stdout nil math.huge math.pi self true]],
|
||||
|
||||
[[assert collectgarbage dofile error getfenv getmetatable ipairs load loadfile loadstring
|
||||
module next pairs pcall print rawequal rawget rawlen rawset require
|
||||
@@ -248,7 +272,8 @@ return {
|
||||
math.floor math.fmod math.frexp math.ldexp math.log math.log10 math.max math.min math.modf
|
||||
math.pow math.rad math.random math.randomseed math.sin math.sinh math.sqrt math.tan math.tanh
|
||||
os.clock os.date os.difftime os.execute os.exit os.getenv os.remove os.rename os.setlocale os.time os.tmpname
|
||||
package.loadlib package.searchpath package.seeall
|
||||
package.loadlib package.searchpath package.seeall package.config
|
||||
package.cpath package.loaded package.loaders package.path package.preload package.searchers
|
||||
string.byte string.char string.dump string.find string.format string.gmatch string.gsub string.len
|
||||
string.lower string.match string.rep string.reverse string.sub string.upper
|
||||
byte find format gmatch gsub len lower match rep reverse sub upper
|
||||
|
||||
@@ -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 = "%.",
|
||||
sep = ".",
|
||||
linecomment = "//",
|
||||
|
||||
isfncall = function(str)
|
||||
return string.find(str, funccall .. "%(")
|
||||
end,
|
||||
|
||||
isfndef = function(str)
|
||||
local l
|
||||
|
||||
@@ -5,7 +5,7 @@ return {
|
||||
exts = {"ptx",},
|
||||
lexer = wxstc.wxSTC_LEX_CPP,
|
||||
apitype = "ptx",
|
||||
sep = "%.",
|
||||
sep = ".",
|
||||
linecomment = "//",
|
||||
|
||||
isfndef = function(str)
|
||||
|
||||
27
src/defs.lua
27
src/defs.lua
@@ -59,7 +59,6 @@ style = {
|
||||
calltip = stattr,
|
||||
|
||||
-- common special (need custom fg & bg )
|
||||
calltipbg = nil,
|
||||
sel = nil,
|
||||
caret = nil,
|
||||
caretlinebg = nil,
|
||||
@@ -124,17 +123,21 @@ 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
|
||||
}
|
||||
},
|
||||
|
||||
format = { -- various formatting strings
|
||||
menurecentprojects = nil,
|
||||
},
|
||||
|
||||
keymap = {}, -- mapping of menu IDs to hot keys
|
||||
messages = {}, -- list of messages in a particular language
|
||||
@@ -146,7 +149,7 @@ config = {
|
||||
interpreter = "luadeb", -- the default "project" lua interpreter
|
||||
|
||||
autocomplete = true, -- whether autocomplete is on by default
|
||||
autoanalizer = true, -- whether auto syntax analizer is on by default
|
||||
autoanalyzer = true, -- whether auto syntax analyzer is on by default
|
||||
|
||||
acandtip = {
|
||||
shorttip = false, -- tooltips are compact during typing
|
||||
@@ -158,7 +161,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 +192,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,
|
||||
-- ...
|
||||
@@ -236,7 +241,7 @@ api = {
|
||||
-- ----------------------------------------------------
|
||||
-- all entries are optional
|
||||
spec = {
|
||||
exts = {"ext","ext2",..},
|
||||
exts = {"ext","ext2",},
|
||||
-- compatible extensions
|
||||
|
||||
lexer = wxstc.wxSTC_LEX_LUA,
|
||||
@@ -247,7 +252,7 @@ spec = {
|
||||
-- appropriate lexer id
|
||||
stringeol = {wxstc.wxSTC_LUA_STRINGEOL,},
|
||||
-- ...
|
||||
}
|
||||
},
|
||||
|
||||
linecomment = "//",
|
||||
-- string for linecomments
|
||||
@@ -258,7 +263,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 +325,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)
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
-- Copyright 2011-14 Paul Kulchenko, ZeroBrane LLC
|
||||
-- authors: Luxinia Dev (Eike Decker & Christoph Kubisch)
|
||||
---------------------------------------------------------
|
||||
|
||||
local ide = ide
|
||||
local statusBar = ide.frame.statusBar
|
||||
|
||||
local q = EscapeMagic
|
||||
|
||||
-- api loading depends on Lua interpreter
|
||||
-- and loaded specs
|
||||
|
||||
@@ -107,11 +111,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 fillTips(api,apibasename,apiname)
|
||||
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)
|
||||
local apiac = api.ac
|
||||
local tclass = api.tip
|
||||
local tipwidth = math.max(20, ide.config.acandtip.width)
|
||||
|
||||
tclass.staticnames = {}
|
||||
tclass.keys = {}
|
||||
@@ -130,28 +147,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")
|
||||
local infshort = (info.type == "value" and "" or frontname.."\n")
|
||||
..(sentence and sentence.."..." or info.description)
|
||||
local inf = ((info.type == "value" and "" or frontname.."\n")
|
||||
..description)
|
||||
local sentence = description:match("^(.-)%. ?\n")
|
||||
local infshort = ((info.type == "value" and "" or frontname.."\n")
|
||||
..(sentence and sentence.."..." or description))
|
||||
local infshortbatch = (info.returns and info.args) and frontname or infshort
|
||||
|
||||
-- add to infoclass
|
||||
@@ -208,15 +217,18 @@ end
|
||||
-- assumes a tidied up string (no spaces, braces..)
|
||||
local function resolveAssign(editor,tx)
|
||||
local ac = editor.api.ac
|
||||
local sep = editor.spec.sep
|
||||
local anysep = "["..q(sep).."]"
|
||||
local assigns = editor.assignscache and editor.assignscache.assigns
|
||||
local function getclass(tab,a)
|
||||
local key,rest = a:match("([%w_]+)[%.:](.*)")
|
||||
local key,rest = a:match("([%w_]+)"..anysep.."(.*)")
|
||||
key = tonumber(key) or key -- make this work for childs[0]
|
||||
if (key and rest and tab.childs and tab.childs[key]) then
|
||||
return getclass(tab.childs[key],rest)
|
||||
end
|
||||
if (tab.valuetype) then
|
||||
return getclass(ac,tab.valuetype.."."..a)
|
||||
-- process valuetype, but only if it doesn't reference the current tab
|
||||
if (tab.valuetype and tab ~= ac.childs[tab.valuetype]) then
|
||||
return getclass(ac,tab.valuetype..sep:sub(1,1)..a)
|
||||
end
|
||||
return tab,a
|
||||
end
|
||||
@@ -229,7 +241,7 @@ local function resolveAssign(editor,tx)
|
||||
local classname = nil
|
||||
c = ""
|
||||
change = false
|
||||
for w,s in tx:gmatch("([%w_]+)([%.:]?)") do
|
||||
for w,s in tx:gmatch("([%w_]+)("..anysep.."?)") do
|
||||
local old = classname
|
||||
-- check if what we have so far can be matched with a class name
|
||||
-- this can happen if it's a reference to a value with a known type
|
||||
@@ -242,11 +254,6 @@ local function resolveAssign(editor,tx)
|
||||
c = c..w..s
|
||||
end
|
||||
end
|
||||
-- abort if the same or recursive value is returned; no need to continue.
|
||||
-- this can happen after typing "smth = smth:new(); smth:" or
|
||||
-- "line = line:gsub(...); line:" as the current algorithm attempts to
|
||||
-- replace "line" with the value that also includes "line"
|
||||
if change and c:find("^"..(tx:gsub("[.:]","[.:]"))) then break end
|
||||
tx = c
|
||||
end
|
||||
else
|
||||
@@ -264,11 +271,13 @@ function GetTipInfo(editor, content, short, fullmatch)
|
||||
|
||||
-- try to resolve the class
|
||||
content = content:gsub("%b[]",".0")
|
||||
local tab, rest = resolveAssign(editor, content)
|
||||
local tab = resolveAssign(editor, content)
|
||||
local sep = editor.spec.sep
|
||||
local anysep = "["..q(sep).."]"
|
||||
|
||||
local caller = content:match("([%w_]+)%(?%s*$")
|
||||
local class = (tab and tab.classname
|
||||
or caller and content:match("([%w_]+)[%.:]"..caller.."%(?%s*$") or "")
|
||||
or caller and content:match("([%w_]+)"..anysep..caller.."%(?%s*$") or "")
|
||||
local tip = editor.api.tip
|
||||
|
||||
local classtab = short and tip.shortfinfoclass or tip.finfoclass
|
||||
@@ -330,13 +339,13 @@ local function addDynamicWord (api,word)
|
||||
if api.tip.keys[word] or api.tip.staticnames[word] then return end
|
||||
local cnt = dywordentries[word]
|
||||
if cnt then
|
||||
dywordentries[word] = cnt +1
|
||||
dywordentries[word] = cnt + 1
|
||||
return
|
||||
end
|
||||
dywordentries[word] = 1
|
||||
local wlow = word:lower()
|
||||
for i=0,#word do
|
||||
local k = wlow : sub (1,i)
|
||||
local k = wlow:sub(1,i)
|
||||
dynamicwords[k] = dynamicwords[k] or {}
|
||||
table.insert(dynamicwords[k], word)
|
||||
end
|
||||
@@ -380,27 +389,28 @@ local function getEditorLines(editor,line,numlines)
|
||||
editor:PositionFromLine(line),editor:PositionFromLine(line+numlines+1))
|
||||
end
|
||||
|
||||
function DynamicWordsAdd(ev,editor,content,line,numlines)
|
||||
function DynamicWordsAdd(editor,content,line,numlines)
|
||||
if ide.config.acandtip.nodynwords then return end
|
||||
local api = editor.api
|
||||
local content = content or getEditorLines(editor,line,numlines)
|
||||
for word in content:gmatch "[%.:]?%s*([a-zA-Z_]+[a-zA-Z_0-9]+)" do
|
||||
local anysep = "["..q(editor.spec.sep).."]"
|
||||
content = content or getEditorLines(editor,line,numlines)
|
||||
for word in content:gmatch(anysep.."?%s*([a-zA-Z_]+[a-zA-Z_0-9]+)") do
|
||||
addDynamicWord(api,word)
|
||||
end
|
||||
end
|
||||
|
||||
function DynamicWordsRem(ev,editor,content,line,numlines)
|
||||
function DynamicWordsRem(editor,content,line,numlines)
|
||||
if ide.config.acandtip.nodynwords then return end
|
||||
local api = editor.api
|
||||
local content = content or getEditorLines(editor,line,numlines)
|
||||
for word in content:gmatch "[%.:]?%s*([a-zA-Z_]+[a-zA-Z_0-9]+)" do
|
||||
local anysep = "["..q(editor.spec.sep).."]"
|
||||
content = content or getEditorLines(editor,line,numlines)
|
||||
for word in content:gmatch(anysep.."?%s*([a-zA-Z_]+[a-zA-Z_0-9]+)") do
|
||||
removeDynamicWord(api,word)
|
||||
end
|
||||
end
|
||||
|
||||
function DynamicWordsRemoveAll (editor)
|
||||
local tx = editor:GetText()
|
||||
DynamicWordsRem("close",editor,tx)
|
||||
function DynamicWordsRemoveAll(editor)
|
||||
DynamicWordsRem(editor,editor:GetText())
|
||||
end
|
||||
|
||||
------------
|
||||
@@ -409,7 +419,6 @@ end
|
||||
local cachemain = {}
|
||||
local cachemethod = {}
|
||||
local laststrategy
|
||||
local lastmethod
|
||||
local function getAutoCompApiList(childs,fragment,method)
|
||||
fragment = fragment:lower()
|
||||
local strategy = ide.config.acandtip.strategy
|
||||
@@ -430,8 +439,8 @@ local function getAutoCompApiList(childs,fragment,method)
|
||||
-- if a:b typed, then value (type == "value") not allowed
|
||||
-- if a.b typed, then method (type == "method") not allowed
|
||||
if type(v) ~= 'table' or (v.type and
|
||||
((method and v.type ~= "value")
|
||||
or (not method and v.type ~= "method"))) then
|
||||
((method and v.type ~= "value")
|
||||
or (not method and v.type ~= "method"))) then
|
||||
wlist = wlist..i.." "
|
||||
end
|
||||
end
|
||||
@@ -465,8 +474,8 @@ local function getAutoCompApiList(childs,fragment,method)
|
||||
-- if a:b typed, then value (type == "value") not allowed
|
||||
-- if a.b typed, then method (type == "method") not allowed
|
||||
if type(v) ~= 'table' or (v.type and
|
||||
((method and v.type ~= "value")
|
||||
or (not method and v.type ~= "method"))) then
|
||||
((method and v.type ~= "value")
|
||||
or (not method and v.type ~= "method"))) then
|
||||
local used = {}
|
||||
--
|
||||
local kl = key:lower()
|
||||
@@ -498,10 +507,6 @@ local function getAutoCompApiList(childs,fragment,method)
|
||||
return t
|
||||
end
|
||||
|
||||
function ClearAutoCompCache()
|
||||
cache = {}
|
||||
end
|
||||
|
||||
-- make syntype dependent
|
||||
function CreateAutoCompList(editor,key)
|
||||
local api = editor.api
|
||||
@@ -509,7 +514,7 @@ function CreateAutoCompList(editor,key)
|
||||
local ac = api.ac
|
||||
local sep = editor.spec.sep
|
||||
|
||||
local method = key:match(":[^"..sep.."]*$") ~= nil
|
||||
local method = key:match(":[^"..q(sep).."]*$") ~= nil
|
||||
|
||||
-- ignore keywords
|
||||
if tip.keys[key] then return end
|
||||
@@ -522,7 +527,7 @@ function CreateAutoCompList(editor,key)
|
||||
if not (progress) then return end
|
||||
|
||||
if (tab == ac) then
|
||||
local _, krest = rest:match("([%w_]+)["..sep.."]([%w_]*)%s*$")
|
||||
local _, krest = rest:match("([%w_]+)["..q(sep).."]([%w_]*)%s*$")
|
||||
if (krest) then
|
||||
tab = #krest >= (ide.config.acandtip.startat or 2) and tip.finfo or {}
|
||||
rest = krest:gsub("[^%w_]","")
|
||||
@@ -555,9 +560,8 @@ function CreateAutoCompList(editor,key)
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
local res = table.concat(list," ")
|
||||
dw = res ~= "" and " "..res or ""
|
||||
|
||||
dw = table.concat(list," ")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -566,7 +570,7 @@ function CreateAutoCompList(editor,key)
|
||||
|
||||
local function addInheritance(tab, apilist, seen)
|
||||
if not tab.inherits then return end
|
||||
for base in tab.inherits:gmatch("[%w_"..sep.."]+") do
|
||||
for base in tab.inherits:gmatch("[%w_"..q(sep).."]+") do
|
||||
local tab = ac
|
||||
-- map "a.b.c" to class hierarchy (a.b.c)
|
||||
for class in base:gmatch("[%w_]+") do tab = tab.childs[class] end
|
||||
@@ -636,7 +640,7 @@ function CreateAutoCompList(editor,key)
|
||||
end
|
||||
|
||||
-- concat final, list complete first
|
||||
local li = (compstr .. dw)
|
||||
|
||||
local li = compstr .. (#compstr > 0 and #dw > 0 and " " or "") .. dw
|
||||
|
||||
return li ~= "" and (#li > 1024 and li:sub(1,1024).."..." or li) or nil
|
||||
end
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
-- Copyright 2011-14 Paul Kulchenko, ZeroBrane LLC
|
||||
-- authors: Lomtik Software (J. Winwood & John Labenski)
|
||||
-- Luxinia Dev (Eike Decker & Christoph Kubisch)
|
||||
---------------------------------------------------------
|
||||
|
||||
local ide = ide
|
||||
local frame = ide.frame
|
||||
local notebook = frame.notebook
|
||||
@@ -10,12 +12,11 @@ local unpack = table.unpack or unpack
|
||||
|
||||
local CURRENT_LINE_MARKER = StylesGetMarker("currentline")
|
||||
local CURRENT_LINE_MARKER_VALUE = 2^CURRENT_LINE_MARKER
|
||||
local BREAKPOINT_MARKER = StylesGetMarker("breakpoint")
|
||||
|
||||
function NewFile(filename)
|
||||
filename = filename or ide.config.default.fullname
|
||||
local editor = CreateEditor()
|
||||
SetupKeywords(editor, GetFileExt(filename))
|
||||
editor:SetupKeywords(GetFileExt(filename))
|
||||
local doc = AddEditor(editor, filename)
|
||||
if doc then
|
||||
PackageEventHandle("onEditorNew", editor)
|
||||
@@ -27,7 +28,7 @@ end
|
||||
-- Find an editor page that hasn't been used at all, eg. an untouched NewFile()
|
||||
local function findUnusedEditor()
|
||||
local editor
|
||||
for id, document in pairs(openDocuments) do
|
||||
for _, document in pairs(openDocuments) do
|
||||
if (document.editor:GetLength() == 0) and
|
||||
(not document.isModified) and (not document.filePath) and
|
||||
not (document.editor:GetReadOnly() == true) then
|
||||
@@ -50,7 +51,8 @@ function LoadFile(filePath, editor, file_must_exist, skipselection)
|
||||
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
|
||||
notebook:SetSelection(doc.index)
|
||||
end
|
||||
return doc.editor
|
||||
end
|
||||
end
|
||||
@@ -69,8 +71,18 @@ function LoadFile(filePath, editor, file_must_exist, skipselection)
|
||||
editor = editor or findUnusedEditor() or CreateEditor()
|
||||
|
||||
editor:Freeze()
|
||||
SetupKeywords(editor, GetFileExt(filePath))
|
||||
editor:SetupKeywords(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;
|
||||
@@ -97,13 +109,16 @@ function LoadFile(filePath, editor, file_must_exist, skipselection)
|
||||
editor:Colourise(0, -1)
|
||||
editor:Thaw()
|
||||
|
||||
local edcfg = ide.config.editor
|
||||
if current then editor:GotoPos(current) end
|
||||
if (file_text and ide.config.editor.autotabs) then
|
||||
local found = string.find(file_text,"\t") ~= nil
|
||||
editor:SetUseTabs(found)
|
||||
if (file_text and edcfg.autotabs) then
|
||||
-- use tabs if they are already used
|
||||
-- or if "usetabs" is set and no space indentation is used in a file
|
||||
editor:SetUseTabs(string.find(file_text, "\t") ~= nil
|
||||
or edcfg.usetabs and (file_text:find("%f[^\r\n] ") or file_text:find("^ ")) == nil)
|
||||
end
|
||||
|
||||
if (file_text and ide.config.editor.checkeol) then
|
||||
if (file_text and edcfg.checkeol) then
|
||||
-- Auto-detect CRLF/LF line-endings
|
||||
local foundcrlf = string.find(file_text,"\r\n") ~= nil
|
||||
local foundlf = (string.find(file_text,"[^\r]\n") ~= nil)
|
||||
@@ -144,11 +159,65 @@ function LoadFile(filePath, editor, file_must_exist, skipselection)
|
||||
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
|
||||
|
||||
function ActivateFile(filename)
|
||||
local name, suffix, value = filename:match('(.+):([lLpP]?)(%d+)$')
|
||||
if name and not wx.wxFileExists(filename) and wx.wxFileExists(name) then
|
||||
filename = name
|
||||
end
|
||||
|
||||
local opened = LoadFile(filename, nil, true)
|
||||
if opened and value then
|
||||
if suffix:upper() == 'P' then opened:GotoPosDelayed(tonumber(value))
|
||||
else opened:GotoPosDelayed(opened:PositionFromLine(value-1))
|
||||
end
|
||||
end
|
||||
return opened
|
||||
end
|
||||
|
||||
local function getExtsString()
|
||||
local knownexts = ""
|
||||
for i,spec in pairs(ide.specs) do
|
||||
for _,spec in pairs(ide.specs) do
|
||||
if (spec.exts) then
|
||||
for n,ext in ipairs(spec.exts) do
|
||||
for _,ext in ipairs(spec.exts) do
|
||||
knownexts = knownexts.."*."..ext..";"
|
||||
end
|
||||
end
|
||||
@@ -164,11 +233,12 @@ function ReportError(msg)
|
||||
end
|
||||
|
||||
function OpenFile(event)
|
||||
local exts = getExtsString()
|
||||
local editor = GetEditor()
|
||||
local path = editor and ide:GetDocument(editor):GetFilePath() or nil
|
||||
local fileDialog = wx.wxFileDialog(ide.frame, TR("Open file"),
|
||||
(path and GetPathWithSep(path) or FileTreeGetDir() or ""),
|
||||
"",
|
||||
"",
|
||||
exts,
|
||||
getExtsString(),
|
||||
wx.wxFD_OPEN + wx.wxFD_FILE_MUST_EXIST)
|
||||
if fileDialog:ShowModal() == wx.wxID_OK then
|
||||
if not LoadFile(fileDialog:GetPath(), nil, true) then
|
||||
@@ -193,13 +263,13 @@ function SaveFile(editor, filePath)
|
||||
if ide.config.savebak then
|
||||
local ok, err = FileRename(filePath, filePath..".bak")
|
||||
if not ok then
|
||||
ReportError(TR("Unable to save file '%s'."):format(filePath..".bak")
|
||||
.."\nError: "..err)
|
||||
ReportError(TR("Unable to save file '%s': %s"):format(filePath..".bak", err))
|
||||
return
|
||||
end
|
||||
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
|
||||
@@ -271,7 +341,7 @@ function SaveFileAs(editor)
|
||||
if ext ~= GetFileExt(filePath) then
|
||||
-- new extension, so setup new keywords and re-apply indicators
|
||||
editor:ClearDocumentStyle() -- remove styles from the document
|
||||
SetupKeywords(editor, GetFileExt(filePath))
|
||||
editor:SetupKeywords(GetFileExt(filePath))
|
||||
IndicateAll(editor)
|
||||
MarkupStyle(editor)
|
||||
end
|
||||
@@ -294,7 +364,7 @@ function SaveFileAs(editor)
|
||||
end
|
||||
|
||||
function SaveAll(quiet)
|
||||
for id, document in pairs(openDocuments) do
|
||||
for _, document in pairs(openDocuments) do
|
||||
local editor = document.editor
|
||||
local filePath = document.filePath
|
||||
|
||||
@@ -422,7 +492,7 @@ function SaveModifiedDialog(editor, allow_cancel)
|
||||
end
|
||||
|
||||
function SaveOnExit(allow_cancel)
|
||||
for id, document in pairs(openDocuments) do
|
||||
for _, document in pairs(openDocuments) do
|
||||
if (SaveModifiedDialog(document.editor, allow_cancel) == wx.wxID_CANCEL) then
|
||||
return false
|
||||
end
|
||||
@@ -472,35 +542,24 @@ function FoldSome()
|
||||
|
||||
if foldall then
|
||||
if foldHdr and editor:GetFoldExpanded(ln) then
|
||||
editor:ToggleFold(ln) end
|
||||
editor:ToggleFold(ln)
|
||||
end
|
||||
elseif hidebase then
|
||||
if not foldHdr and (foldLvl == wxstc.wxSTC_FOLDLEVELBASE) then
|
||||
editor:HideLines(ln, ln) end
|
||||
editor:HideLines(ln, ln)
|
||||
end
|
||||
else -- unfold all
|
||||
if foldHdr and not editor:GetFoldExpanded(ln) then
|
||||
editor:ToggleFold(ln) end
|
||||
editor:ToggleFold(ln)
|
||||
end
|
||||
end
|
||||
end
|
||||
editor:EnsureCaretVisible()
|
||||
end
|
||||
|
||||
function EnsureRangeVisible(posStart, posEnd)
|
||||
local editor = GetEditor()
|
||||
if posStart > posEnd then
|
||||
posStart, posEnd = posEnd, posStart
|
||||
end
|
||||
|
||||
local lineStart = editor:LineFromPosition(posStart)
|
||||
local lineEnd = editor:LineFromPosition(posEnd)
|
||||
for line = lineStart, lineEnd do
|
||||
editor:EnsureVisibleEnforcePolicy(line)
|
||||
end
|
||||
end
|
||||
|
||||
function SetAllEditorsReadOnly(enable)
|
||||
for id, document in pairs(openDocuments) do
|
||||
local editor = document.editor
|
||||
editor:SetReadOnly(enable)
|
||||
for _, document in pairs(openDocuments) do
|
||||
document.editor:SetReadOnly(enable)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -508,9 +567,8 @@ end
|
||||
-- Debug related
|
||||
|
||||
function ClearAllCurrentLineMarkers()
|
||||
for id, document in pairs(openDocuments) do
|
||||
local editor = document.editor
|
||||
editor:MarkerDeleteAll(CURRENT_LINE_MARKER)
|
||||
for _, document in pairs(openDocuments) do
|
||||
document.editor:MarkerDeleteAll(CURRENT_LINE_MARKER)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -521,14 +579,19 @@ function StripShebang(code) return (code:gsub("^#!.-\n", "\n")) end
|
||||
|
||||
local compileOk, compileTotal = 0, 0
|
||||
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 params = {
|
||||
jumponerror = (params or {}).jumponerror ~= false,
|
||||
reportstats = (params or {}).reportstats ~= false,
|
||||
keepoutput = (params or {}).keepoutput,
|
||||
}
|
||||
local doc = ide:GetDocument(editor)
|
||||
local filePath = doc:GetFilePath() or doc:GetFileName()
|
||||
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
|
||||
if not params.keepoutput and ide.frame.menuBar:IsChecked(ID_CLEAROUTPUT) then
|
||||
ClearOutput()
|
||||
end
|
||||
|
||||
compileTotal = compileTotal + 1
|
||||
if func then
|
||||
@@ -540,7 +603,23 @@ function CompileProgram(editor, params)
|
||||
else
|
||||
DisplayOutputLn(TR("Compilation error").." "..TR("on line %d"):format(line)..":")
|
||||
DisplayOutputLn((err:gsub("\n$", "")))
|
||||
if line and params.jumponerror then editor:GotoLine(line-1) end
|
||||
-- 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 func ~= nil -- return true if it compiled ok
|
||||
@@ -576,7 +655,7 @@ end
|
||||
|
||||
function GetOpenFiles()
|
||||
local opendocs = {}
|
||||
for id, document in pairs(ide.openDocuments) do
|
||||
for _, document in pairs(ide.openDocuments) do
|
||||
if (document.filePath) then
|
||||
local wxfname = wx.wxFileName(document.filePath)
|
||||
wxfname:Normalize()
|
||||
@@ -595,7 +674,7 @@ function GetOpenFiles()
|
||||
end
|
||||
|
||||
function SetOpenFiles(nametab,params)
|
||||
for i,doc in ipairs(nametab) do
|
||||
for _, doc in ipairs(nametab) do
|
||||
local editor = LoadFile(doc.filename,nil,true,true) -- skip selection
|
||||
if editor then editor:GotoPosDelayed(doc.cursorpos or 0) end
|
||||
end
|
||||
@@ -604,6 +683,8 @@ function SetOpenFiles(nametab,params)
|
||||
end
|
||||
|
||||
local beforeFullScreenPerspective
|
||||
local statusbarShown
|
||||
|
||||
function ShowFullScreen(setFullScreen)
|
||||
if setFullScreen then
|
||||
beforeFullScreenPerspective = uimgr:SavePerspective()
|
||||
@@ -620,21 +701,24 @@ function ShowFullScreen(setFullScreen)
|
||||
beforeFullScreenPerspective = nil
|
||||
end
|
||||
|
||||
-- On OSX, toolbar and status bar are not hidden when switched to
|
||||
-- On OSX, status bar is not hidden when switched to
|
||||
-- full screen: http://trac.wxwidgets.org/ticket/14259; do manually.
|
||||
-- need to turn off before showing full screen and turn on after,
|
||||
-- otherwise the window is restored incorrectly and is reduced in size.
|
||||
if ide.osname == 'Macintosh' and setFullScreen then
|
||||
statusbarShown = frame:GetStatusBar():IsShown()
|
||||
frame:GetStatusBar():Hide()
|
||||
frame:GetToolBar():Hide()
|
||||
end
|
||||
|
||||
-- protect from systems that don't have ShowFullScreen (GTK on linux?)
|
||||
pcall(function() frame:ShowFullScreen(setFullScreen) end)
|
||||
|
||||
if ide.osname == 'Macintosh' and not setFullScreen then
|
||||
frame:GetStatusBar():Show()
|
||||
frame:GetToolBar():Show()
|
||||
if statusbarShown then
|
||||
frame:GetStatusBar():Show()
|
||||
-- refresh AuiManager as the statusbar may be shown below the border
|
||||
uimgr:Update()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -644,25 +728,32 @@ 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
|
||||
end
|
||||
DisplayOutputLn(TR("Found auto-recovery record and restored saved session."))
|
||||
if not params.quiet then
|
||||
DisplayOutputLn(TR("Found auto-recovery record and restored saved session."))
|
||||
end
|
||||
for _,doc in ipairs(nametab) do
|
||||
local editor = doc.filename and LoadFile(doc.filename,nil,true,true) or NewFile()
|
||||
local opendoc = openDocuments[editor:GetId()]
|
||||
if doc.content then
|
||||
notebook:SetPageText(opendoc.index, doc.tabname)
|
||||
editor:SetText(doc.content)
|
||||
if doc.filename and opendoc.modTime and doc.modified < opendoc.modTime:GetTicks() then
|
||||
DisplayOutputLn(TR("File '%s' has more recent timestamp than restored '%s'; please review before saving.")
|
||||
:format(doc.filename, doc.tabname))
|
||||
-- check for missing file is no content is stored
|
||||
if doc.filepath and not doc.content and not wx.wxFileExists(doc.filepath) then
|
||||
DisplayOutputLn(TR("File '%s' is missing and can't be recovered.")
|
||||
:format(doc.filepath))
|
||||
else
|
||||
local editor = doc.filepath and LoadFile(doc.filepath,nil,true,true) or NewFile(doc.filename)
|
||||
local opendoc = openDocuments[editor:GetId()]
|
||||
if doc.content then
|
||||
editor:SetText(doc.content)
|
||||
if doc.filepath and opendoc.modTime and doc.modified < opendoc.modTime:GetTicks() then
|
||||
DisplayOutputLn(TR("File '%s' has more recent timestamp than restored '%s'; please review before saving.")
|
||||
:format(doc.filepath, doc.tabname))
|
||||
end
|
||||
SetDocumentModified(editor:GetId(), true)
|
||||
end
|
||||
editor:GotoPosDelayed(doc.cursorpos or 0)
|
||||
end
|
||||
editor:GotoPosDelayed(doc.cursorpos or 0)
|
||||
end
|
||||
notebook:SetSelection(params and params.index or 0)
|
||||
SetEditorSelection()
|
||||
@@ -670,9 +761,10 @@ end
|
||||
|
||||
local function getOpenTabs()
|
||||
local opendocs = {}
|
||||
for id, document in pairs(ide.openDocuments) do
|
||||
for _, document in pairs(ide.openDocuments) do
|
||||
table.insert(opendocs, {
|
||||
filename = document.filePath,
|
||||
filename = document.fileName,
|
||||
filepath = document.filePath,
|
||||
tabname = notebook:GetPageText(document.index),
|
||||
modified = document.modTime and document.modTime:GetTicks(), -- get number of seconds
|
||||
content = document.isModified and document.editor:GetText() or nil,
|
||||
@@ -691,21 +783,39 @@ function SetAutoRecoveryMark()
|
||||
ide.session.lastupdated = os.time()
|
||||
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 function generateRecoveryRecord(opentabs)
|
||||
return require('mobdebug').line(opentabs, {comment = false})
|
||||
end
|
||||
|
||||
local function saveHotExit()
|
||||
local opentabs, params = getOpenTabs()
|
||||
if #opentabs > 0 then
|
||||
params.recovery = generateRecoveryRecord(opentabs)
|
||||
params.quiet = true
|
||||
SettingsSaveFileSession({}, params)
|
||||
end
|
||||
end
|
||||
|
||||
local function saveAutoRecovery(force)
|
||||
if not ide.config.autorecoverinactivity then return end
|
||||
|
||||
local lastupdated = ide.session.lastupdated
|
||||
if not force then
|
||||
if not lastupdated or lastupdated < (ide.session.lastsaved or 0) then return end
|
||||
end
|
||||
|
||||
local now = os.time()
|
||||
if not force and lastupdated + ide.config.autorecoverinactivity > now then return end
|
||||
|
||||
-- find all open modified files and save them
|
||||
local opentabs, params = getOpenTabs()
|
||||
if #opentabs > 0 then
|
||||
params.recovery = require('mobdebug').line(opentabs, {comment = false})
|
||||
params.recovery = generateRecoveryRecord(opentabs)
|
||||
SettingsSaveAll()
|
||||
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
|
||||
@@ -764,7 +874,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
|
||||
|
||||
@@ -795,7 +905,7 @@ local function closeWindow(event)
|
||||
|
||||
ide.exitingProgram = true -- don't handle focus events
|
||||
|
||||
if not SaveOnExit(event:CanVeto()) then
|
||||
if not ide.config.hotexit and not SaveOnExit(event:CanVeto()) then
|
||||
event:Veto()
|
||||
ide.exitingProgram = false
|
||||
return
|
||||
@@ -805,7 +915,14 @@ local function closeWindow(event)
|
||||
|
||||
PackageEventHandle("onAppClose")
|
||||
|
||||
-- first need to detach all processes IDE has launched as the current
|
||||
-- process is likely to terminate before child processes are terminated,
|
||||
-- which may lead to a crash when EVT_END_PROCESS event is called.
|
||||
DetachChildProcess()
|
||||
DebuggerShutdown()
|
||||
|
||||
SettingsSaveAll()
|
||||
if ide.config.hotexit then saveHotExit() end
|
||||
ide.settings:Flush()
|
||||
|
||||
do -- hide all floating panes first
|
||||
@@ -819,23 +936,80 @@ local function closeWindow(event)
|
||||
frame.uimgr:UnInit()
|
||||
frame:Hide() -- hide the main frame while the IDE exits
|
||||
|
||||
-- first need to detach all processes IDE has launched as the current
|
||||
-- process is likely to terminate before child processes are terminated,
|
||||
-- which may lead to a crash when EVT_END_PROCESS event is called.
|
||||
DetachChildProcess()
|
||||
DebuggerShutdown()
|
||||
|
||||
if ide.session.timer then ide.session.timer:Stop() end
|
||||
|
||||
event:Skip()
|
||||
end
|
||||
frame:Connect(wx.wxEVT_CLOSE_WINDOW, closeWindow)
|
||||
|
||||
frame:Connect(wx.wxEVT_TIMER, saveAutoRecovery)
|
||||
frame:Connect(wx.wxEVT_TIMER, function() saveAutoRecovery() end)
|
||||
|
||||
-- in the presence of wxAuiToolbar, when (1) the app gets focus,
|
||||
-- (2) a floating panel is closed or (3) a toolbar dropdown is closed,
|
||||
-- the focus is always on the toolbar when the app gets focus,
|
||||
-- so to restore the focus correctly, need to track where the control is
|
||||
-- and to set the focus to the last element that had focus.
|
||||
-- it would be easier to track KILL_FOCUS events, but controls on OSX
|
||||
-- don't always generate KILL_FOCUS events (see relevant wxwidgets
|
||||
-- tickets: http://trac.wxwidgets.org/ticket/14142
|
||||
-- and http://trac.wxwidgets.org/ticket/14269)
|
||||
|
||||
local infocus
|
||||
ide.editorApp:Connect(wx.wxEVT_SET_FOCUS, function(event)
|
||||
if ide.exitingProgram then return end
|
||||
|
||||
local win = ide.frame:FindFocus()
|
||||
if win then
|
||||
local class = win:GetClassInfo():GetClassName()
|
||||
-- don't set focus on the main frame or toolbar
|
||||
if infocus and (class == 'wxAuiToolBar' or class == 'wxFrame') then
|
||||
pcall(function() infocus:SetFocus() end)
|
||||
return
|
||||
end
|
||||
|
||||
-- keep track of the current control in focus, but only on the main frame
|
||||
-- don't try to "remember" any of the focus changes on various dialog
|
||||
-- windows as those will disappear along with their controls
|
||||
local grandparent = win:GetGrandParent()
|
||||
local frameid = ide.frame:GetId()
|
||||
local mainwin = grandparent and grandparent:GetId() == frameid
|
||||
local parent = win:GetParent()
|
||||
while parent do
|
||||
local class = parent:GetClassInfo():GetClassName()
|
||||
if (class == 'wxFrame' or class:find('^wx.*Dialog$'))
|
||||
and parent:GetId() ~= frameid then
|
||||
mainwin = false; break
|
||||
end
|
||||
parent = parent:GetParent()
|
||||
end
|
||||
if mainwin then
|
||||
if infocus and infocus ~= win and ide.osname == 'Macintosh' then
|
||||
-- kill focus on the control that had the focus as wxwidgets on OSX
|
||||
-- doesn't do it: http://trac.wxwidgets.org/ticket/14142;
|
||||
-- wrap into pcall in case the window is already deleted
|
||||
local ev = wx.wxFocusEvent(wx.wxEVT_KILL_FOCUS)
|
||||
pcall(function() infocus:GetEventHandler():ProcessEvent(ev) end)
|
||||
end
|
||||
infocus = win
|
||||
end
|
||||
end
|
||||
|
||||
event:Skip()
|
||||
end)
|
||||
|
||||
ide.editorApp:Connect(wx.wxEVT_ACTIVATE_APP,
|
||||
function(event)
|
||||
if not ide.exitingProgram then
|
||||
if ide.osname == 'Macintosh' and infocus and event:GetActive() then
|
||||
-- restore focus to the last element that received it;
|
||||
-- wrap into pcall in case the element has disappeared
|
||||
-- while the application was out of focus
|
||||
pcall(function() infocus:SetFocus() end)
|
||||
end
|
||||
|
||||
-- save auto-recovery record when making the app inactive
|
||||
if not event:GetActive() then saveAutoRecovery(true) end
|
||||
|
||||
local event = event:GetActive() and "onAppFocusSet" or "onAppFocusLost"
|
||||
PackageEventHandle(event, ide.editorApp)
|
||||
end
|
||||
@@ -847,3 +1021,15 @@ if ide.config.autorecoverinactivity then
|
||||
-- check at least 5s to be never more than 5s off
|
||||
ide.session.timer:Start(math.min(5, ide.config.autorecoverinactivity)*1000)
|
||||
end
|
||||
|
||||
function PaneFloatToggle(window)
|
||||
local pane = uimgr:GetPane(window)
|
||||
if pane:IsFloating() then
|
||||
pane:Dock()
|
||||
else
|
||||
pane:Float()
|
||||
pane:FloatingPosition(pane.window:GetScreenPosition())
|
||||
pane:FloatingSize(pane.window:GetSize())
|
||||
end
|
||||
uimgr:Update()
|
||||
end
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
-- Integration with MobDebug
|
||||
-- Copyright 2011-13 Paul Kulchenko, ZeroBrane LLC
|
||||
-- Copyright 2011-14 Paul Kulchenko, ZeroBrane LLC
|
||||
-- Original authors: Lomtik Software (J. Winwood & John Labenski)
|
||||
-- Luxinia Dev (Eike Decker & Christoph Kubisch)
|
||||
-- Integration with MobDebug
|
||||
---------------------------------------------------------
|
||||
|
||||
local copas = require "copas"
|
||||
local socket = require "socket"
|
||||
@@ -9,19 +10,32 @@ local mobdebug = require "mobdebug"
|
||||
local unpack = table.unpack or unpack
|
||||
|
||||
local ide = ide
|
||||
local debugger = ide.debugger
|
||||
local debugger = setmetatable(ide.debugger, ide.proto.Debugger)
|
||||
debugger.server = nil -- DebuggerServer object when debugging, else nil
|
||||
debugger.running = false -- true when the debuggee is running
|
||||
debugger.listening = false -- true when the debugger is listening for a client
|
||||
debugger.portnumber = ide.config.debugger.port or mobdebug.port -- the port # to use for debugging
|
||||
debugger.watchCtrl = nil -- the watch ctrl that shows watch information
|
||||
debugger.stackCtrl = nil -- the stack ctrl that shows stack information
|
||||
debugger.toggleview = { stackpanel = false, watchpanel = false }
|
||||
debugger.toggleview = {
|
||||
stackpanel = false, watchpanel = false, toolbar = false }
|
||||
debugger.hostname = ide.config.debugger.hostname or (function()
|
||||
local hostname = socket.dns.gethostname()
|
||||
return hostname and socket.dns.toip(hostname) and hostname or "localhost"
|
||||
end)()
|
||||
|
||||
local image = { STACK = 0, LOCAL = 1, UPVALUE = 2 }
|
||||
|
||||
do
|
||||
local getBitmap = (ide.app.createbitmap or wx.wxArtProvider.GetBitmap)
|
||||
local size = wx.wxSize(16,16)
|
||||
local imglist = wx.wxImageList(16,16)
|
||||
imglist:Add(getBitmap("GO-FORWARD", "OTHER", size)) -- 0 = stack call
|
||||
imglist:Add(getBitmap("LIST-VIEW", "OTHER", size)) -- 1 = local variables
|
||||
imglist:Add(getBitmap("REPORT-VIEW", "OTHER", size)) -- 2 = upvalues
|
||||
debugger.imglist = imglist
|
||||
end
|
||||
|
||||
local notebook = ide.frame.notebook
|
||||
|
||||
local CURRENT_LINE_MARKER = StylesGetMarker("currentline")
|
||||
@@ -56,7 +70,7 @@ end
|
||||
|
||||
local q = EscapeMagic
|
||||
|
||||
local function updateWatchesSync(num)
|
||||
local function updateWatchesSync(onlyitem)
|
||||
local watchCtrl = debugger.watchCtrl
|
||||
local pane = ide.frame.uimgr:GetPane("watchpanel")
|
||||
local shown = watchCtrl and (pane:IsOk() and pane:IsShown() or not pane:IsOk() and watchCtrl:IsShown())
|
||||
@@ -65,43 +79,55 @@ local function updateWatchesSync(num)
|
||||
local bgcl = watchCtrl:GetBackgroundColour()
|
||||
local hicl = wx.wxColour(math.floor(bgcl:Red()*.9),
|
||||
math.floor(bgcl:Green()*.9), math.floor(bgcl:Blue()*.9))
|
||||
for idx = 0, watchCtrl:GetItemCount() - 1 do
|
||||
if not num or idx == num then
|
||||
local expression = watchCtrl:GetItemText(idx)
|
||||
local _, values, error = debugger.evaluate(expression)
|
||||
if error then error = error:gsub("%[.-%]:%d+:%s+","")
|
||||
elseif #values == 0 then values = {'nil'} end
|
||||
|
||||
local newval = error and ('error: '..error) or values[1]
|
||||
-- get the current value from a list item
|
||||
do local litem = wx.wxListItem()
|
||||
litem:SetMask(wx.wxLIST_MASK_TEXT)
|
||||
litem:SetId(idx)
|
||||
litem:SetColumn(1)
|
||||
watchCtrl:GetItem(litem)
|
||||
watchCtrl:SetItemBackgroundColour(idx,
|
||||
watchCtrl:GetItem(litem) and newval ~= litem:GetText()
|
||||
and hicl or bgcl)
|
||||
local root = watchCtrl:GetRootItem()
|
||||
if not root or not root:IsOk() then return end
|
||||
|
||||
local item = onlyitem or watchCtrl:GetFirstChild(root)
|
||||
while true do
|
||||
if not item:IsOk() then break end
|
||||
|
||||
local expression = watchCtrl:GetItemExpression(item)
|
||||
if expression then
|
||||
local _, values, error = debugger.evaluate(expression)
|
||||
local curchildren = watchCtrl:GetItemChildren(item)
|
||||
if error then
|
||||
error = error:gsub("%[.-%]:%d+:%s+","")
|
||||
watchCtrl:SetItemValueIfExpandable(item, nil)
|
||||
else
|
||||
if #values == 0 then values = {'nil'} end
|
||||
local ok, res = LoadSafe("return "..values[1])
|
||||
watchCtrl:SetItemValueIfExpandable(item, res)
|
||||
end
|
||||
|
||||
watchCtrl:SetItem(idx, 1, newval)
|
||||
local newval = (expression .. ' = '
|
||||
.. (error and ('error: '..error) or table.concat(values, ", ")))
|
||||
local val = watchCtrl:GetItemText(item)
|
||||
|
||||
watchCtrl:SetItemBackgroundColour(item, val ~= newval and hicl or bgcl)
|
||||
watchCtrl:SetItemText(item, newval)
|
||||
|
||||
if onlyitem or val ~= newval then
|
||||
local newchildren = watchCtrl:GetItemChildren(item)
|
||||
if next(curchildren) ~= nil and next(newchildren) == nil then
|
||||
watchCtrl:SetItemHasChildren(item, true)
|
||||
watchCtrl:CollapseAndReset(item)
|
||||
watchCtrl:SetItemHasChildren(item, false)
|
||||
elseif next(curchildren) ~= nil and next(newchildren) ~= nil then
|
||||
watchCtrl:CollapseAndReset(item)
|
||||
watchCtrl:Expand(item)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if onlyitem then break end
|
||||
item = watchCtrl:GetNextSibling(item)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local simpleType = {['nil'] = true, ['string'] = true, ['number'] = true, ['boolean'] = true}
|
||||
local stackItemValue = {}
|
||||
local callData = {}
|
||||
local function checkIfExpandable(value, item)
|
||||
local expandable = type(value) == 'table' and next(value) ~= nil
|
||||
and not stackItemValue[value] -- only expand first time
|
||||
if expandable then -- cache table value to expand when requested
|
||||
stackItemValue[item:GetValue()] = value
|
||||
stackItemValue[value] = item:GetValue() -- to avoid circular refs
|
||||
end
|
||||
return expandable
|
||||
end
|
||||
|
||||
local function updateStackSync()
|
||||
local stackCtrl = debugger.stackCtrl
|
||||
@@ -111,17 +137,16 @@ local function updateStackSync()
|
||||
and not debugger.scratchpad then
|
||||
local stack, _, err = debugger.stack()
|
||||
if not stack or #stack == 0 then
|
||||
stackCtrl:DeleteAllItems()
|
||||
stackCtrl:DeleteAll()
|
||||
if err then -- report an error if any
|
||||
stackCtrl:AppendItem(stackCtrl:AddRoot("Stack"), "Error: " .. err, 0)
|
||||
stackCtrl:AppendItem(stackCtrl:AddRoot("Stack"), "Error: " .. err, image.STACK)
|
||||
end
|
||||
return
|
||||
end
|
||||
stackCtrl:Freeze()
|
||||
stackCtrl:DeleteAllItems()
|
||||
stackCtrl:DeleteAll()
|
||||
|
||||
local root = stackCtrl:AddRoot("Stack")
|
||||
stackItemValue = {} -- reset cache of items in the stack
|
||||
callData = {} -- reset call cache
|
||||
for _,frame in ipairs(stack) do
|
||||
-- "main chunk at line 24"
|
||||
@@ -144,7 +169,7 @@ local function updateStackSync()
|
||||
or " (defined in "..call[7]..")"))
|
||||
|
||||
-- create the new tree item for this level of the call stack
|
||||
local callitem = stackCtrl:AppendItem(root, text, 0)
|
||||
local callitem = stackCtrl:AppendItem(root, text, image.STACK)
|
||||
|
||||
-- register call data to provide stack navigation
|
||||
callData[callitem:GetValue()] = { call[2], call[4] }
|
||||
@@ -160,10 +185,8 @@ local function updateStackSync()
|
||||
local text = ("%s = %s%s"):
|
||||
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
|
||||
stackCtrl:SetItemHasChildren(item, true)
|
||||
end
|
||||
local item = stackCtrl:AppendItem(callitem, text, image.LOCAL)
|
||||
stackCtrl:SetItemValueIfExpandable(item, value)
|
||||
end
|
||||
|
||||
-- add the upvalues for this call stack level to the tree item
|
||||
@@ -172,10 +195,8 @@ local function updateStackSync()
|
||||
local text = ("%s = %s%s"):
|
||||
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
|
||||
stackCtrl:SetItemHasChildren(item, true)
|
||||
end
|
||||
local item = stackCtrl:AppendItem(callitem, text, image.UPVALUE)
|
||||
stackCtrl:SetItemValueIfExpandable(item, value)
|
||||
end
|
||||
|
||||
stackCtrl:SortChildren(callitem)
|
||||
@@ -196,12 +217,12 @@ local function updateStackAndWatches()
|
||||
end
|
||||
end
|
||||
|
||||
local function updateWatches(num)
|
||||
local function updateWatches(item)
|
||||
-- check if the debugger is running and may be waiting for a response.
|
||||
-- allow that request to finish, otherwise updateWatchesSync() does nothing.
|
||||
if debugger.running then debugger.update() end
|
||||
if debugger.server and not debugger.running then
|
||||
copas.addthread(function() updateWatchesSync(num) end)
|
||||
copas.addthread(function() updateWatchesSync(item) end)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -209,10 +230,12 @@ local function debuggerToggleViews(show)
|
||||
local mgr = ide.frame.uimgr
|
||||
local refresh = false
|
||||
for view, needed in pairs(debugger.toggleview) do
|
||||
local bar = view == 'toolbar'
|
||||
local pane = mgr:GetPane(view)
|
||||
if show then -- starting debugging and pane is not shown
|
||||
debugger.toggleview[view] = not pane:IsShown()
|
||||
if debugger.toggleview[view] and needed then
|
||||
if debugger.toggleview[view] and (needed or bar)
|
||||
and (not bar or not ide.frame:IsFullScreen()) then
|
||||
pane:Show()
|
||||
refresh = true
|
||||
end
|
||||
@@ -393,10 +416,7 @@ debugger.shell = function(expression, isstatement)
|
||||
local addedret, forceexpression = true, expression:match("^%s*=%s*")
|
||||
expression = expression:gsub("^%s*=%s*","")
|
||||
local _, values, err = debugger.evaluate(expression)
|
||||
if not forceexpression and err and
|
||||
(err:find("'?<eof>'? expected near '") or
|
||||
err:find("'%(' expected near") or
|
||||
err:find("unexpected symbol near '")) then
|
||||
if not forceexpression and err then
|
||||
_, values, err = debugger.execute(expression)
|
||||
addedret = false
|
||||
end
|
||||
@@ -406,7 +426,6 @@ debugger.shell = function(expression, isstatement)
|
||||
DisplayShellErr(err)
|
||||
elseif addedret or #values > 0 then
|
||||
if forceexpression then -- display elements as multi-line
|
||||
local mobdebug = require "mobdebug"
|
||||
for i,v in pairs(values) do -- stringify each of the returned values
|
||||
local func = loadstring('return '..v) -- deserialize the value first
|
||||
if func then -- if it's deserialized correctly
|
||||
@@ -427,8 +446,11 @@ debugger.shell = function(expression, isstatement)
|
||||
|
||||
-- refresh Stack and Watch windows if executed a statement (and no err)
|
||||
if isstatement and not err and not addedret and #values == 0 then
|
||||
updateStackSync() updateWatchesSync() end
|
||||
updateStackSync() updateWatchesSync()
|
||||
end
|
||||
end)
|
||||
elseif debugger.server then
|
||||
DisplayShellErr(TR("Can't evaluate the expression while the application is running."))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -442,8 +464,66 @@ local function stoppedAtBreakpoint(file, line)
|
||||
return breakpoint > -1 and breakpoint == current
|
||||
end
|
||||
|
||||
debugger.listen = function()
|
||||
local server = socket.bind("*", debugger.portnumber)
|
||||
local function mapRemotePath(basedir, file, line, method)
|
||||
if not file then return end
|
||||
|
||||
-- file is /foo/bar/my.lua; basedir is d:\local\path\
|
||||
-- check for d:\local\path\my.lua, d:\local\path\bar\my.lua, ...
|
||||
-- wxwidgets on Windows handles \\ and / as separators, but on OSX
|
||||
-- and Linux it only handles 'native' separator;
|
||||
-- need to translate for GetDirs to work.
|
||||
local file = file:gsub("\\", "/")
|
||||
local parts = wx.wxFileName(file):GetDirs()
|
||||
local name = wx.wxFileName(file):GetFullName()
|
||||
|
||||
-- find the longest remote path that can be mapped locally
|
||||
local longestpath, remotedir
|
||||
while true do
|
||||
local mapped = GetFullPathIfExists(basedir, name)
|
||||
if mapped then
|
||||
longestpath = mapped
|
||||
remotedir = file:gsub(q(name):gsub("/", ".").."$", "")
|
||||
end
|
||||
if #parts == 0 then break end
|
||||
name = table.remove(parts, #parts) .. "/" .. name
|
||||
end
|
||||
|
||||
-- if found a local mapping under basedir
|
||||
local activated = longestpath and activateDocument(longestpath, line, method or activate.NOREPORT)
|
||||
if activated then
|
||||
-- find remote basedir by removing the tail from remote file
|
||||
debugger.handle("basedir " .. debugger.basedir .. "\t" .. remotedir)
|
||||
-- reset breakpoints again as remote basedir has changed
|
||||
reSetBreakpoints()
|
||||
DisplayOutputLn(TR("Mapped remote request for '%s' to '%s'.")
|
||||
:format(remotedir, debugger.basedir))
|
||||
|
||||
return longestpath
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
debugger.listen = function(start)
|
||||
if start == false then
|
||||
if debugger.listening then
|
||||
debugger.terminate() -- terminate if running
|
||||
copas.removeserver(debugger.listening)
|
||||
DisplayOutputLn(TR("Debugger server stopped at %s:%d.")
|
||||
:format(debugger.hostname, debugger.portnumber))
|
||||
debugger.listening = false
|
||||
else
|
||||
DisplayOutputLn(TR("Can't stop debugger server as it is not started."))
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
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
|
||||
@@ -471,7 +551,8 @@ debugger.listen = function()
|
||||
if not options.allowediting then options.allowediting = ide.config.debugger.allowediting end
|
||||
|
||||
if not debugger.scratchpad and not options.allowediting then
|
||||
SetAllEditorsReadOnly(true) end
|
||||
SetAllEditorsReadOnly(true)
|
||||
end
|
||||
|
||||
debugger.server = copas.wrap(skt)
|
||||
debugger.socket = skt
|
||||
@@ -482,7 +563,7 @@ debugger.listen = function()
|
||||
debugger.editormap = {}
|
||||
|
||||
local wxfilepath = GetEditorFileAndCurInfo()
|
||||
local startfile = options.startfile or options.startwith
|
||||
local startfile = options.startwith
|
||||
or (wxfilepath and wxfilepath:GetFullPath())
|
||||
|
||||
if not startfile then
|
||||
@@ -500,6 +581,12 @@ debugger.listen = function()
|
||||
-- set basedir first, before loading to make sure that the path is correct
|
||||
debugger.handle("basedir " .. debugger.basedir)
|
||||
|
||||
local init = options.init or ide.config.debugger.init
|
||||
if init then
|
||||
local _, _, err = debugger.execute(init)
|
||||
if err then DisplayOutputLn(TR("Ignored error in debugger initialization code: %s."):format(err)) end
|
||||
end
|
||||
|
||||
reSetBreakpoints()
|
||||
|
||||
local redirect = ide.config.debugger.redirect or options.redirect
|
||||
@@ -509,10 +596,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
|
||||
@@ -558,8 +644,11 @@ debugger.listen = function()
|
||||
..":\n"..err)
|
||||
return debugger.terminate()
|
||||
elseif options.runstart then
|
||||
if stoppedAtBreakpoint(file or startfile, line or 0) then
|
||||
activateDocument(file or startfile, line or 0)
|
||||
local file = (mapRemotePath(basedir, file, line or 0, activate.CHECKONLY)
|
||||
or file or startfile)
|
||||
|
||||
if stoppedAtBreakpoint(file, line or 0) then
|
||||
activateDocument(file, line or 0)
|
||||
options.runstart = false
|
||||
end
|
||||
elseif file and line then
|
||||
@@ -582,36 +671,8 @@ debugger.listen = function()
|
||||
-- when autoactivation is disabled.
|
||||
if not activated and (not wx.wxFileName(file):FileExists()
|
||||
or wx.wxIsAbsolutePath(file)) then
|
||||
-- file is /foo/bar/my.lua; basedir is d:\local\path\
|
||||
-- check for d:\local\path\my.lua, d:\local\path\bar\my.lua, ...
|
||||
-- wxwidgets on Windows handles \\ and / as separators, but on OSX
|
||||
-- and Linux it only handles 'native' separator;
|
||||
-- need to translate for GetDirs to work.
|
||||
local file = file:gsub("\\", "/")
|
||||
local parts = wx.wxFileName(file):GetDirs()
|
||||
local name = wx.wxFileName(file):GetFullName()
|
||||
|
||||
-- find the longest remote path that can be mapped locally
|
||||
local longestpath, remotedir
|
||||
while true do
|
||||
local mapped = GetFullPathIfExists(basedir, name)
|
||||
if mapped then
|
||||
longestpath = mapped
|
||||
remotedir = file:gsub(q(name):gsub("/", ".").."$", "")
|
||||
end
|
||||
if #parts == 0 then break end
|
||||
name = table.remove(parts, #parts) .. "/" .. name
|
||||
end
|
||||
|
||||
-- if found a local mapping under basedir
|
||||
activated = longestpath and activateDocument(longestpath, line, activate.NOREPORT)
|
||||
if activated then
|
||||
-- find remote basedir by removing the tail from remote file
|
||||
debugger.handle("basedir " .. debugger.basedir .. "\t" .. remotedir)
|
||||
-- reset breakpoints again as remote basedir has changed
|
||||
reSetBreakpoints()
|
||||
DisplayOutputLn(TR("Mapped remote request for '%s' to '%s'.")
|
||||
:format(remotedir, debugger.basedir))
|
||||
if mapRemotePath(basedir, file, line, activate.NOREPORT) then
|
||||
activated = true
|
||||
end
|
||||
end
|
||||
|
||||
@@ -653,20 +714,31 @@ debugger.listen = function()
|
||||
end
|
||||
end
|
||||
end)
|
||||
debugger.listening = true
|
||||
debugger.listening = server
|
||||
end
|
||||
|
||||
local function nameOutputTab(name)
|
||||
local nbk = ide.frame.bottomnotebook
|
||||
local index = nbk:GetPageIndex(ide:GetOutput())
|
||||
if index then nbk:SetPageText(index, name) end
|
||||
end
|
||||
|
||||
debugger.handle = function(command, server, options)
|
||||
local verbose = ide.config.debugger.verbose
|
||||
local osexit, gprint
|
||||
osexit, os.exit = os.exit, function () end
|
||||
gprint, _G.print = _G.print, function (...) if verbose then DisplayOutputLn(...) end end
|
||||
gprint, _G.print = _G.print, function (...)
|
||||
if verbose then DisplayOutputLn(...) end
|
||||
end
|
||||
|
||||
nameOutputTab(TR("Output (running)"))
|
||||
debugger.running = true
|
||||
if verbose then DisplayOutputLn("Debugger sent (command):", command) end
|
||||
local file, line, err = mobdebug.handle(command, server or debugger.server, options)
|
||||
if verbose then DisplayOutputLn("Debugger received (file, line, err):", file, line, err) end
|
||||
debugger.running = false
|
||||
-- only set suspended if the debugging hasn't been terminated
|
||||
if debugger.server then nameOutputTab(TR("Output (suspended)")) end
|
||||
|
||||
os.exit = osexit
|
||||
_G.print = gprint
|
||||
@@ -742,6 +814,18 @@ debugger.handleAsync = function(command)
|
||||
copas.addthread(function () debugger.handle(command) end)
|
||||
end
|
||||
end
|
||||
debugger.handleDirect = function(command)
|
||||
local sock = debugger.socket
|
||||
if debugger.server and sock then
|
||||
local running = debugger.running
|
||||
-- this needs to be short as it will block the UI
|
||||
sock:settimeout(0.25)
|
||||
debugger.handle(command, sock)
|
||||
sock:settimeout(0)
|
||||
-- restore running status
|
||||
debugger.running = running
|
||||
end
|
||||
end
|
||||
|
||||
debugger.loadfile = function(file)
|
||||
return debugger.handle("load " .. file)
|
||||
@@ -753,13 +837,21 @@ 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 = unpack(debugger.activate)
|
||||
if content then
|
||||
@@ -769,9 +861,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
|
||||
@@ -796,6 +893,7 @@ end
|
||||
debugger.over = function() debugger.exec("over") end
|
||||
debugger.out = function() debugger.exec("out") end
|
||||
debugger.run = function() debugger.exec("run") end
|
||||
debugger.detach = function() debugger.exec("done") end
|
||||
debugger.evaluate = function(expression) return debugger.handle('eval ' .. expression) end
|
||||
debugger.execute = function(expression) return debugger.handle('exec ' .. expression) end
|
||||
debugger.stack = function() return debugger.handle('stack') end
|
||||
@@ -822,7 +920,10 @@ debugger.breaknow = function(command)
|
||||
end
|
||||
end
|
||||
debugger.breakpoint = function(file, line, state)
|
||||
debugger.handleAsync((state and "setb " or "delb ") .. file .. " " .. line)
|
||||
if debugger.running then
|
||||
return debugger.handleDirect((state and "asetb " or "adelb ") .. file .. " " .. line)
|
||||
end
|
||||
return debugger.handleAsync((state and "setb " or "delb ") .. file .. " " .. line)
|
||||
end
|
||||
debugger.quickeval = function(var, callback)
|
||||
if debugger.server and not debugger.running
|
||||
@@ -837,56 +938,56 @@ debugger.quickeval = function(var, callback)
|
||||
end
|
||||
end
|
||||
|
||||
-- need imglist to be a file local variable as SetImageList takes ownership
|
||||
-- of it and if done inside a function, icons do not work as expected
|
||||
local imglist = wx.wxImageList(16,16)
|
||||
do
|
||||
local getBitmap = (ide.app.createbitmap or wx.wxArtProvider.GetBitmap)
|
||||
local size = wx.wxSize(16,16)
|
||||
-- 0 = stack call
|
||||
imglist:Add(getBitmap(wx.wxART_GO_FORWARD, wx.wxART_OTHER, size))
|
||||
-- 1 = local variables
|
||||
imglist:Add(getBitmap(wx.wxART_LIST_VIEW, wx.wxART_OTHER, size))
|
||||
-- 2 = upvalues
|
||||
imglist:Add(getBitmap(wx.wxART_REPORT_VIEW, wx.wxART_OTHER, size))
|
||||
function DebuggerAddStackWindow()
|
||||
return ide:AddPanel(debugger.stackCtrl, "stackpanel", TR("Stack"))
|
||||
end
|
||||
|
||||
function DebuggerAddWatchWindow()
|
||||
return ide:AddPanel(debugger.watchCtrl, "watchpanel", TR("Watch"))
|
||||
end
|
||||
|
||||
local width, height = 360, 200
|
||||
|
||||
function debuggerAddWindow(ctrl, panel, name)
|
||||
local notebook = wxaui.wxAuiNotebook(ide.frame, wx.wxID_ANY,
|
||||
wx.wxDefaultPosition, wx.wxDefaultSize,
|
||||
wxaui.wxAUI_NB_DEFAULT_STYLE + wxaui.wxAUI_NB_TAB_EXTERNAL_MOVE
|
||||
- wxaui.wxAUI_NB_CLOSE_ON_ACTIVE_TAB + wx.wxNO_BORDER)
|
||||
notebook:AddPage(ctrl, TR(name), true)
|
||||
local keyword = {}
|
||||
for _,k in ipairs({'and', 'break', 'do', 'else', 'elseif', 'end', 'false',
|
||||
'for', 'function', 'goto', 'if', 'in', 'local', 'nil', 'not', 'or', 'repeat',
|
||||
'return', 'then', 'true', 'until', 'while'}) do keyword[k] = true end
|
||||
|
||||
local mgr = ide.frame.uimgr
|
||||
mgr:AddPane(notebook, wxaui.wxAuiPaneInfo():
|
||||
Name(panel):Float():
|
||||
MinSize(width/2,height/2):
|
||||
BestSize(width,height):FloatingSize(width,height):
|
||||
PinButton(true):Hide())
|
||||
mgr.defaultPerspective = mgr:SavePerspective() -- resave default perspective
|
||||
|
||||
return notebook
|
||||
local function stringifyKeyIntoPrefix(name, num)
|
||||
return (type(name) == "number"
|
||||
and (num and num == name and '' or ("[%s] = "):format(name))
|
||||
or type(name) == "string" and (name:match("^[%l%u_][%w_]*$") and not keyword[name]
|
||||
and ("%s = "):format(name)
|
||||
or ("[%q] = "):format(name))
|
||||
or ("[%s] = "):format(tostring(name)))
|
||||
end
|
||||
|
||||
function DebuggerAddStackWindow()
|
||||
return debuggerAddWindow(debugger.stackCtrl, "stackpanel", "Stack")
|
||||
end
|
||||
|
||||
function DebuggerAddWatchWindow()
|
||||
return debuggerAddWindow(debugger.watchCtrl, "watchpanel", "Watch")
|
||||
end
|
||||
|
||||
function debuggerCreateStackWindow()
|
||||
local function debuggerCreateStackWindow()
|
||||
local stackCtrl = wx.wxTreeCtrl(ide.frame, wx.wxID_ANY,
|
||||
wx.wxDefaultPosition, wx.wxSize(width, height),
|
||||
wx.wxTR_LINES_AT_ROOT + wx.wxTR_HAS_BUTTONS + wx.wxTR_SINGLE + wx.wxTR_HIDE_ROOT)
|
||||
|
||||
debugger.stackCtrl = stackCtrl
|
||||
|
||||
stackCtrl:SetImageList(imglist)
|
||||
stackCtrl:SetImageList(debugger.imglist)
|
||||
|
||||
local valuecache = {}
|
||||
function stackCtrl:SetItemValueIfExpandable(item, value)
|
||||
local expandable = type(value) == 'table' and next(value) ~= nil
|
||||
if expandable then -- cache table value to expand when requested
|
||||
valuecache[item:GetValue()] = value
|
||||
end
|
||||
self:SetItemHasChildren(item, expandable)
|
||||
end
|
||||
|
||||
function stackCtrl:DeleteAll()
|
||||
self:DeleteAllItems()
|
||||
valuecache = {}
|
||||
end
|
||||
|
||||
function stackCtrl:GetItemChildren(item)
|
||||
return valuecache[item:GetValue()] or {}
|
||||
end
|
||||
|
||||
stackCtrl:Connect(wx.wxEVT_COMMAND_TREE_ITEM_EXPANDING,
|
||||
function (event)
|
||||
@@ -896,15 +997,12 @@ function debuggerCreateStackWindow()
|
||||
|
||||
local image = stackCtrl:GetItemImage(item_id)
|
||||
local num = 1
|
||||
for name,value in pairs(stackItemValue[item_id:GetValue()]) do
|
||||
for name,value in pairs(stackCtrl:GetItemChildren(item_id)) do
|
||||
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)
|
||||
local text = stringifyKeyIntoPrefix(name, num)..strval
|
||||
local item = stackCtrl:AppendItem(item_id, text, image)
|
||||
if checkIfExpandable(value, item) then
|
||||
stackCtrl:SetItemHasChildren(item, true)
|
||||
end
|
||||
stackCtrl:SetItemValueIfExpandable(item, value)
|
||||
|
||||
num = num + 1
|
||||
if num > stackmaxnum then break end
|
||||
end
|
||||
@@ -938,94 +1036,193 @@ function debuggerCreateStackWindow()
|
||||
end
|
||||
|
||||
local function debuggerCreateWatchWindow()
|
||||
local watchCtrl = wx.wxListCtrl(ide.frame, wx.wxID_ANY,
|
||||
wx.wxDefaultPosition, wx.wxDefaultSize,
|
||||
wx.wxLC_REPORT + wx.wxLC_EDIT_LABELS)
|
||||
local watchCtrl = wx.wxTreeCtrl(ide.frame, wx.wxID_ANY,
|
||||
wx.wxDefaultPosition, wx.wxSize(width, height),
|
||||
wx.wxTR_LINES_AT_ROOT + wx.wxTR_HAS_BUTTONS + wx.wxTR_SINGLE
|
||||
+ wx.wxTR_HIDE_ROOT + wx.wxTR_EDIT_LABELS)
|
||||
|
||||
debugger.watchCtrl = watchCtrl
|
||||
|
||||
local info = wx.wxListItem()
|
||||
info:SetMask(wx.wxLIST_MASK_TEXT + wx.wxLIST_MASK_WIDTH)
|
||||
info:SetText(TR("Expression"))
|
||||
info:SetWidth(width * 0.32)
|
||||
watchCtrl:InsertColumn(0, info)
|
||||
local root = watchCtrl:AddRoot("Watch")
|
||||
watchCtrl:SetImageList(debugger.imglist)
|
||||
|
||||
info:SetText(TR("Value"))
|
||||
info:SetWidth(width * 0.56)
|
||||
watchCtrl:InsertColumn(1, info)
|
||||
local defaultExpr = "watch expression"
|
||||
local expressions = {} -- table to keep track of expressions
|
||||
|
||||
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) },
|
||||
}
|
||||
function watchCtrl:SetItemExpression(item, expr, value)
|
||||
expressions[item:GetValue()] = expr
|
||||
self:SetItemText(item, expr .. ' = ' .. (value or '?'))
|
||||
self:SelectItem(item, true)
|
||||
if not value then updateWatches(item) end
|
||||
end
|
||||
|
||||
local function findSelectedWatchItem()
|
||||
local count = watchCtrl:GetSelectedItemCount()
|
||||
if count > 0 then
|
||||
for idx = 0, watchCtrl:GetItemCount() - 1 do
|
||||
if watchCtrl:GetItemState(idx, wx.wxLIST_STATE_FOCUSED) ~= 0 then
|
||||
return idx
|
||||
end
|
||||
end
|
||||
function watchCtrl:GetItemExpression(item)
|
||||
return expressions[item:GetValue()]
|
||||
end
|
||||
|
||||
local names = {}
|
||||
function watchCtrl:SetItemName(item, name)
|
||||
local nametype = type(name)
|
||||
names[item:GetValue()] = (
|
||||
(nametype == 'string' or nametype == 'number' or nametype == 'boolean')
|
||||
and name or nil
|
||||
)
|
||||
end
|
||||
|
||||
function watchCtrl:GetItemName(item)
|
||||
return names[item:GetValue()]
|
||||
end
|
||||
|
||||
local valuecache = {}
|
||||
function watchCtrl:SetItemValueIfExpandable(item, value)
|
||||
local expandable = type(value) == 'table' and next(value) ~= nil
|
||||
valuecache[item:GetValue()] = expandable and value or nil
|
||||
self:SetItemHasChildren(item, expandable)
|
||||
end
|
||||
|
||||
function watchCtrl:GetItemChildren(item)
|
||||
return valuecache[item:GetValue()] or {}
|
||||
end
|
||||
|
||||
function watchCtrl:IsWatch(item)
|
||||
return item:IsOk() and watchCtrl:GetItemParent(item):GetValue() == root:GetValue()
|
||||
end
|
||||
|
||||
function watchCtrl:IsEditable(item)
|
||||
return (item and item:IsOk()
|
||||
and (watchCtrl:IsWatch(item) or watchCtrl:GetItemName(item) ~= nil))
|
||||
end
|
||||
|
||||
function watchCtrl:UpdateItemValue(item, value)
|
||||
local expr = ''
|
||||
local origitem = item
|
||||
while true do
|
||||
local name = watchCtrl:GetItemName(item)
|
||||
expr = (watchCtrl:IsWatch(item)
|
||||
and ('({%s})[1]'):format(watchCtrl:GetItemExpression(item))
|
||||
or (type(name) == 'string' and '[%q]' or '[%s]'):format(tostring(name))
|
||||
)..expr
|
||||
if watchCtrl:IsWatch(item) then break end
|
||||
item = watchCtrl:GetItemParent(item)
|
||||
if not item:IsOk() then break end
|
||||
end
|
||||
|
||||
if debugger.running then debugger.update() end
|
||||
if debugger.server and not debugger.running
|
||||
and (not debugger.scratchpad or debugger.scratchpad.paused) then
|
||||
copas.addthread(function ()
|
||||
local _, _, err = debugger.execute(expr..'='..value)
|
||||
if err then
|
||||
watchCtrl:SetItemText(origitem, 'error: '..err:gsub("%[.-%]:%d+:%s+",""))
|
||||
else
|
||||
updateWatchesSync(item)
|
||||
end
|
||||
updateStackSync()
|
||||
end)
|
||||
end
|
||||
return -1
|
||||
end
|
||||
|
||||
local defaultExpr = ""
|
||||
local function addWatch()
|
||||
local row = watchCtrl:InsertItem(watchCtrl:GetItemCount(), TR("Expr"))
|
||||
watchCtrl:SetItem(row, 0, defaultExpr)
|
||||
watchCtrl:SetItem(row, 1, TR("Value"))
|
||||
watchCtrl:EditLabel(row)
|
||||
end
|
||||
|
||||
local function editWatch()
|
||||
local row = findSelectedWatchItem()
|
||||
if row >= 0 then watchCtrl:EditLabel(row) end
|
||||
end
|
||||
|
||||
local function deleteWatch()
|
||||
local row = findSelectedWatchItem()
|
||||
if row >= 0 then watchCtrl:DeleteItem(row) end
|
||||
end
|
||||
|
||||
watchCtrl:Connect(wx.wxEVT_CONTEXT_MENU,
|
||||
function (event) watchCtrl:PopupMenu(watchMenu) end)
|
||||
|
||||
watchCtrl:Connect(wx.wxEVT_KEY_DOWN,
|
||||
watchCtrl:Connect(wx.wxEVT_COMMAND_TREE_ITEM_EXPANDING,
|
||||
function (event)
|
||||
local keycode = event:GetKeyCode()
|
||||
if (keycode == wx.WXK_DELETE) then return deleteWatch()
|
||||
elseif (keycode == wx.WXK_INSERT) then return addWatch()
|
||||
elseif (keycode == wx.WXK_F2) then return editWatch()
|
||||
local item_id = event:GetItem()
|
||||
local count = watchCtrl:GetChildrenCount(item_id, false)
|
||||
if count > 0 then return true end
|
||||
|
||||
local image = watchCtrl:GetItemImage(item_id)
|
||||
local num = 1
|
||||
for name,value in pairs(watchCtrl:GetItemChildren(item_id)) do
|
||||
local strval = fixUTF8(trimToMaxLength(serialize(value, params)))
|
||||
local text = stringifyKeyIntoPrefix(name, num)..strval
|
||||
local item = watchCtrl:AppendItem(item_id, text, image)
|
||||
watchCtrl:SetItemValueIfExpandable(item, value)
|
||||
watchCtrl:SetItemName(item, name)
|
||||
|
||||
num = num + 1
|
||||
if num > stackmaxnum then break end
|
||||
end
|
||||
event:Skip()
|
||||
return true
|
||||
end)
|
||||
|
||||
watchCtrl:Connect(ID_ADDWATCH, wx.wxEVT_COMMAND_MENU_SELECTED, addWatch)
|
||||
|
||||
watchCtrl:Connect(ID_EDITWATCH, wx.wxEVT_COMMAND_MENU_SELECTED, editWatch)
|
||||
watchCtrl:Connect(ID_EDITWATCH, wx.wxEVT_UPDATE_UI,
|
||||
function (event) event:Enable(watchCtrl:GetSelectedItemCount() > 0) end)
|
||||
|
||||
watchCtrl:Connect(ID_DELETEWATCH, wx.wxEVT_COMMAND_MENU_SELECTED, deleteWatch)
|
||||
watchCtrl:Connect(ID_DELETEWATCH, wx.wxEVT_UPDATE_UI,
|
||||
function (event) event:Enable(watchCtrl:GetSelectedItemCount() > 0) end)
|
||||
|
||||
watchCtrl:Connect(wx.wxEVT_COMMAND_LIST_ITEM_ACTIVATED,
|
||||
function (event) watchCtrl:EditLabel(event:GetIndex()) end)
|
||||
|
||||
watchCtrl:Connect(wx.wxEVT_COMMAND_LIST_END_LABEL_EDIT,
|
||||
watchCtrl:Connect(wx.wxEVT_COMMAND_TREE_DELETE_ITEM,
|
||||
function (event)
|
||||
local row = event:GetIndex()
|
||||
local value = event:GetItem():GetValue()
|
||||
expressions[value] = nil
|
||||
valuecache[value] = nil
|
||||
names[value] = nil
|
||||
end)
|
||||
|
||||
local item
|
||||
-- wx.wxEVT_CONTEXT_MENU is only triggered over tree items on OSX,
|
||||
-- but it needs to be also triggered below any item to add a watch,
|
||||
-- so use RIGHT_DOWN instead
|
||||
watchCtrl:Connect(wx.wxEVT_RIGHT_DOWN,
|
||||
function (event)
|
||||
-- store the item to be used in edit/delete actions
|
||||
item = watchCtrl:HitTest(watchCtrl:ScreenToClient(wx.wxGetMousePosition()))
|
||||
local editlabel = watchCtrl:IsWatch(item) and TR("&Edit Watch") or TR("&Edit Value")
|
||||
watchCtrl:PopupMenu(wx.wxMenu {
|
||||
{ ID_ADDWATCH, TR("&Add Watch")..KSC(ID_ADDWATCH) },
|
||||
{ ID_EDITWATCH, editlabel..KSC(ID_EDITWATCH) },
|
||||
{ ID_DELETEWATCH, TR("&Delete Watch")..KSC(ID_DELETEWATCH) },
|
||||
})
|
||||
item = nil
|
||||
end)
|
||||
|
||||
watchCtrl:Connect(ID_ADDWATCH, wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
function (event) watchCtrl:EditLabel(watchCtrl:AppendItem(root, defaultExpr, image.LOCAL)) end)
|
||||
|
||||
watchCtrl:Connect(ID_EDITWATCH, wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
function (event) watchCtrl:EditLabel(item or watchCtrl:GetSelection()) end)
|
||||
watchCtrl:Connect(ID_EDITWATCH, wx.wxEVT_UPDATE_UI,
|
||||
function (event) event:Enable(watchCtrl:IsEditable(item or watchCtrl:GetSelection())) end)
|
||||
|
||||
watchCtrl:Connect(ID_DELETEWATCH, wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
function (event) watchCtrl:Delete(item or watchCtrl:GetSelection()) end)
|
||||
watchCtrl:Connect(ID_DELETEWATCH, wx.wxEVT_UPDATE_UI,
|
||||
function (event) event:Enable(watchCtrl:IsWatch(item or watchCtrl:GetSelection())) end)
|
||||
|
||||
local label
|
||||
watchCtrl:Connect(wx.wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT,
|
||||
function (event)
|
||||
local item = event:GetItem()
|
||||
if not (item:IsOk() and watchCtrl:IsEditable(item)) then
|
||||
event:Veto()
|
||||
return
|
||||
end
|
||||
|
||||
label = watchCtrl:GetItemText(item)
|
||||
|
||||
if watchCtrl:IsWatch(item) then
|
||||
local expr = watchCtrl:GetItemExpression(item)
|
||||
if expr then watchCtrl:SetItemText(item, expr) end
|
||||
else
|
||||
local prefix = stringifyKeyIntoPrefix(watchCtrl:GetItemName(item))
|
||||
local val = watchCtrl:GetItemText(item):gsub(q(prefix),'')
|
||||
watchCtrl:SetItemText(item, val)
|
||||
end
|
||||
end)
|
||||
watchCtrl:Connect(wx.wxEVT_COMMAND_TREE_END_LABEL_EDIT,
|
||||
function (event)
|
||||
event:Veto()
|
||||
|
||||
local item = event:GetItem()
|
||||
if event:IsEditCancelled() then
|
||||
if watchCtrl:GetItemText(row) == defaultExpr then
|
||||
watchCtrl:DeleteItem(row)
|
||||
if watchCtrl:GetItemText(item) == defaultExpr then
|
||||
-- when Delete is called from END_EDIT, it causes infinite loop
|
||||
-- on OSX (wxwidgets 2.9.5) as Delete calls END_EDIT again.
|
||||
-- disable handlers during Delete and then enable back.
|
||||
watchCtrl:SetEvtHandlerEnabled(false)
|
||||
watchCtrl:Delete(item)
|
||||
watchCtrl:SetEvtHandlerEnabled(true)
|
||||
else
|
||||
watchCtrl:SetItemText(item, label)
|
||||
end
|
||||
else
|
||||
watchCtrl:SetItem(row, 0, event:GetText())
|
||||
updateWatches(row)
|
||||
if watchCtrl:IsWatch(item) then
|
||||
watchCtrl:SetItemExpression(item, event:GetLabel())
|
||||
else
|
||||
watchCtrl:UpdateItemValue(item, event:GetLabel())
|
||||
end
|
||||
end
|
||||
event:Skip()
|
||||
end)
|
||||
@@ -1046,27 +1243,6 @@ debuggerCreateWatchWindow()
|
||||
|
||||
DebuggerRefreshPanels = updateStackAndWatches
|
||||
|
||||
function DebuggerAddWatch(watch)
|
||||
local mgr = ide.frame.uimgr
|
||||
local pane = mgr:GetPane("watchpanel")
|
||||
if (pane:IsOk() and not pane:IsShown()) then
|
||||
pane:Show()
|
||||
mgr:Update()
|
||||
end
|
||||
|
||||
local watchCtrl = debugger.watchCtrl
|
||||
-- check if this expression is already on the list
|
||||
for idx = 0, watchCtrl:GetItemCount() - 1 do
|
||||
if watchCtrl:GetItemText(idx) == watch then return end
|
||||
end
|
||||
|
||||
local row = watchCtrl:InsertItem(watchCtrl:GetItemCount(), TR("Expr"))
|
||||
watchCtrl:SetItem(row, 0, watch)
|
||||
watchCtrl:SetItem(row, 1, TR("Value"))
|
||||
|
||||
updateWatches(row)
|
||||
end
|
||||
|
||||
function DebuggerAttachDefault(options)
|
||||
debugger.options = options
|
||||
if (debugger.listening) then return end
|
||||
@@ -1078,10 +1254,9 @@ function DebuggerShutdown()
|
||||
if debugger.pid then killClient() end
|
||||
end
|
||||
|
||||
function DebuggerStop()
|
||||
function DebuggerStop(resetpid)
|
||||
if (debugger.server) then
|
||||
debugger.server = nil
|
||||
debugger.pid = nil
|
||||
SetAllEditorsReadOnly(false)
|
||||
ShellSupportRemote(nil)
|
||||
ClearAllCurrentLineMarkers()
|
||||
@@ -1095,19 +1270,20 @@ function DebuggerStop()
|
||||
-- no debugger.server, but scratchpad may still be on. Turn it off.
|
||||
DebuggerScratchpadOff()
|
||||
end
|
||||
-- reset pid for "running" (not debugged) processes
|
||||
if resetpid then debugger.pid = nil end
|
||||
end
|
||||
|
||||
function DebuggerMakeFileName(editor, filePath)
|
||||
return filePath or ide.config.default.fullname
|
||||
local function debuggerMakeFileName(editor)
|
||||
return ide:GetDocument(editor):GetFilePath()
|
||||
or ide:GetDocument(editor):GetFileName()
|
||||
or ide.config.default.fullname
|
||||
end
|
||||
|
||||
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)
|
||||
local id = editor:GetId()
|
||||
local filePath = debugger.editormap and debugger.editormap[editor]
|
||||
or DebuggerMakeFileName(editor, ide.openDocuments[id].filePath)
|
||||
or debuggerMakeFileName(editor)
|
||||
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
|
||||
@@ -1123,7 +1299,9 @@ function DebuggerRefreshScratchpad()
|
||||
if debugger.scratchpad and debugger.scratchpad.updated and not debugger.scratchpad.paused then
|
||||
|
||||
local scratchpadEditor = debugger.scratchpad.editor
|
||||
if not ide.interpreter.skipcompile
|
||||
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
|
||||
|
||||
@@ -1138,8 +1316,7 @@ function DebuggerRefreshScratchpad()
|
||||
end
|
||||
else
|
||||
local clear = ide.frame.menuBar:IsChecked(ID_CLEAROUTPUT)
|
||||
local filePath = DebuggerMakeFileName(scratchpadEditor,
|
||||
ide.openDocuments[scratchpadEditor:GetId()].filePath)
|
||||
local filePath = debuggerMakeFileName(scratchpadEditor)
|
||||
|
||||
-- wrap into a function call to make "return" to work with scratchpad
|
||||
code = "(function()"..code.."\nend)()"
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
-- Copyright 2011-13 Paul Kulchenko, ZeroBrane LLC
|
||||
-- Copyright 2011-14 Paul Kulchenko, ZeroBrane LLC
|
||||
-- authors: Lomtik Software (J. Winwood & John Labenski)
|
||||
-- Luxinia Dev (Eike Decker & Christoph Kubisch)
|
||||
---------------------------------------------------------
|
||||
local wxkeywords = nil -- a string of the keywords for scintilla of wxLua's wx.XXX items
|
||||
|
||||
local editorID = 100 -- window id to create editor pages with, incremented for new editors
|
||||
|
||||
@@ -12,9 +11,26 @@ 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 }
|
||||
local linenummask = "99999"
|
||||
local foldtypes = {
|
||||
[0] = { wxstc.wxSTC_MARKNUM_FOLDEROPEN, wxstc.wxSTC_MARKNUM_FOLDER,
|
||||
wxstc.wxSTC_MARKNUM_FOLDERSUB, wxstc.wxSTC_MARKNUM_FOLDERTAIL, wxstc.wxSTC_MARKNUM_FOLDEREND,
|
||||
wxstc.wxSTC_MARKNUM_FOLDEROPENMID, wxstc.wxSTC_MARKNUM_FOLDERMIDTAIL,
|
||||
},
|
||||
box = { wxstc.wxSTC_MARK_BOXMINUS, wxstc.wxSTC_MARK_BOXPLUS,
|
||||
wxstc.wxSTC_MARK_VLINE, wxstc.wxSTC_MARK_LCORNER, wxstc.wxSTC_MARK_BOXPLUSCONNECTED,
|
||||
wxstc.wxSTC_MARK_BOXMINUSCONNECTED, wxstc.wxSTC_MARK_TCORNER,
|
||||
},
|
||||
circle = { wxstc.wxSTC_MARK_CIRCLEMINUS, wxstc.wxSTC_MARK_CIRCLEPLUS,
|
||||
wxstc.wxSTC_MARK_VLINE, wxstc.wxSTC_MARK_LCORNERCURVE, wxstc.wxSTC_MARK_CIRCLEPLUSCONNECTED,
|
||||
wxstc.wxSTC_MARK_CIRCLEMINUSCONNECTED, wxstc.wxSTC_MARK_TCORNERCURVE,
|
||||
},
|
||||
plus = { wxstc.wxSTC_MARK_MINUS, wxstc.wxSTC_MARK_PLUS },
|
||||
arrow = { wxstc.wxSTC_MARK_ARROWDOWN, wxstc.wxSTC_MARK_ARROW },
|
||||
}
|
||||
|
||||
-- ----------------------------------------------------------------------------
|
||||
-- Update the statusbar text of the frame using the given editor.
|
||||
@@ -29,15 +45,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]
|
||||
@@ -66,8 +88,8 @@ local function updateBraceMatch(editor)
|
||||
if (pos) then
|
||||
-- don't match brackets in markup comments
|
||||
local style = bit.band(editor:GetStyleAt(pos), 31)
|
||||
if MarkupIsSpecial and MarkupIsSpecial(style)
|
||||
or editor.spec.iscomment[style] then return end
|
||||
if (MarkupIsSpecial and MarkupIsSpecial(style)
|
||||
or editor.spec.iscomment[style]) then return end
|
||||
|
||||
local pos2 = editor:BraceMatch(pos)
|
||||
if (pos2 == wxstc.wxSTC_INVALID_POSITION) then
|
||||
@@ -83,15 +105,6 @@ local function updateBraceMatch(editor)
|
||||
end
|
||||
end
|
||||
|
||||
local function getFileTitle (editor)
|
||||
if not editor or not openDocuments[editor:GetId()] then return GetIDEString("editor") end
|
||||
local id = editor:GetId()
|
||||
local filePath = openDocuments[id].filePath
|
||||
local fileName = openDocuments[id].fileName
|
||||
if not filePath or not fileName then return GetIDEString("editor") end
|
||||
return GetIDEString("editor").." ["..filePath.."]"
|
||||
end
|
||||
|
||||
-- Check if file is altered, show dialog to reload it
|
||||
local function isFileAlteredOnDisk(editor)
|
||||
if not editor then return end
|
||||
@@ -118,7 +131,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
|
||||
@@ -128,7 +141,7 @@ end
|
||||
|
||||
local function navigateToPosition(editor, fromPosition, toPosition, length)
|
||||
table.insert(editor.jumpstack, fromPosition)
|
||||
editor:GotoPos(toPosition)
|
||||
editor:GotoPosEnforcePolicy(toPosition)
|
||||
if length then
|
||||
editor:SetAnchor(toPosition + length)
|
||||
end
|
||||
@@ -137,7 +150,8 @@ end
|
||||
local function navigateBack(editor)
|
||||
if #editor.jumpstack == 0 then return end
|
||||
local pos = table.remove(editor.jumpstack)
|
||||
editor:GotoPos(pos)
|
||||
editor:GotoPosEnforcePolicy(pos)
|
||||
return true
|
||||
end
|
||||
|
||||
-- ----------------------------------------------------------------------------
|
||||
@@ -159,7 +173,7 @@ function SetEditorSelection(selection)
|
||||
local editor = GetEditor(selection)
|
||||
updateStatusText(editor) -- update even if nil
|
||||
statusBar:SetStatusText("",1)
|
||||
ide.frame:SetTitle(getFileTitle(editor))
|
||||
ide.frame:SetTitle(ExpandPlaceholders(ide.config.format.apptitle))
|
||||
|
||||
if editor then
|
||||
if funclist:IsEmpty() then funclist:Append(TR("Jump to a function definition..."), 0) end
|
||||
@@ -239,6 +253,14 @@ function EditorAutoComplete(editor)
|
||||
|
||||
-- know now which string is to be completed
|
||||
local userList = CreateAutoCompList(editor,lt)
|
||||
|
||||
-- remove any suggestions that match the word the cursor is on
|
||||
-- for example, if typing 'foo' in front of 'bar', 'foobar' is not offered
|
||||
local right = linetx:sub(localpos+1,#linetx):match("^([%a_]+[%w_]*)")
|
||||
if userList and right then
|
||||
userList = userList:gsub("%f[%w_]"..lt..right.."%f[%W]",""):gsub(" +"," ")
|
||||
end
|
||||
|
||||
-- don't show the list if it only suggests what's already typed
|
||||
if userList and #userList > 0 and not lt:find(userList.."$") then
|
||||
editor:UserListShow(1, userList)
|
||||
@@ -306,6 +328,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
|
||||
@@ -330,7 +384,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.
|
||||
@@ -341,7 +396,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
|
||||
|
||||
@@ -356,7 +411,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
|
||||
|
||||
@@ -412,7 +467,7 @@ function IndicateIfNeeded()
|
||||
local editor = GetEditor()
|
||||
-- do the current one first
|
||||
if delayed[editor] then return IndicateAll(editor) end
|
||||
for editor in pairs(delayed) do return IndicateAll(editor) end
|
||||
for ed in pairs(delayed) do return IndicateAll(ed) end
|
||||
end
|
||||
|
||||
-- find all instances of a symbol at pos
|
||||
@@ -428,7 +483,8 @@ local function indicateFindInstances(editor, name, pos)
|
||||
if this and token.fpos > pos and this == token.at+1 then break end
|
||||
|
||||
if #instances > 1 and instances[#instances][-1] == token.at+1 then
|
||||
table.remove(instances) end
|
||||
table.remove(instances)
|
||||
end
|
||||
elseif token.name == name then
|
||||
if op == 'Id' then
|
||||
table.insert(instances[#instances], token.fpos)
|
||||
@@ -456,9 +512,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
|
||||
@@ -503,9 +562,12 @@ function IndicateAll(editor, lines, linee)
|
||||
while vars do
|
||||
for name, var in pairs(vars) do
|
||||
-- remove all variables that are created later than the current pos
|
||||
while type(var) == 'table' and var.fpos and (var.fpos > pos) do
|
||||
var = var.masked -- restored a masked var
|
||||
vars[name] = var
|
||||
-- skip all non-variable elements from the vars table
|
||||
if type(name) == 'string' then
|
||||
while type(var) == 'table' and var.fpos and (var.fpos > pos) do
|
||||
var = var.masked -- restored a masked var
|
||||
vars[name] = var
|
||||
end
|
||||
end
|
||||
end
|
||||
vars = getmetatable(vars) and getmetatable(vars).__index
|
||||
@@ -570,7 +632,7 @@ function IndicateAll(editor, lines, linee)
|
||||
end
|
||||
|
||||
-- clear indicators till the end of processed fragment
|
||||
local pos = delayed[editor] and delayed[editor][1] or editor:GetLength()+1
|
||||
pos = delayed[editor] and delayed[editor][1] or editor:GetLength()+1
|
||||
|
||||
-- don't clear "masked" indicators as those can be set out of order (so
|
||||
-- last updated fragment is not always the last in terms of its position);
|
||||
@@ -580,98 +642,130 @@ function IndicateAll(editor, lines, linee)
|
||||
return delayed[editor] ~= nil -- request more events if still need to work
|
||||
end
|
||||
|
||||
if ide.wxver < "2.9.5" or not ide.config.autoanalizer then
|
||||
IndicateAll = indicateFunctions28 end
|
||||
if ide.wxver < "2.9.5" or not ide.config.autoanalyzer then
|
||||
IndicateAll = indicateFunctionsOnly
|
||||
end
|
||||
|
||||
-- ----------------------------------------------------------------------------
|
||||
-- Create an editor
|
||||
function CreateEditor()
|
||||
local editor = wxstc.wxStyledTextCtrl(notebook, editorID,
|
||||
wx.wxDefaultPosition, wx.wxSize(0, 0),
|
||||
wx.wxBORDER_STATIC)
|
||||
wx.wxBORDER_NONE)
|
||||
|
||||
editorID = editorID + 1 -- increment so they're always unique
|
||||
|
||||
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)$')
|
||||
local key = shortcut:match('^Ctrl[-+](.)$')
|
||||
if key then editor.ctrlcache[key:byte()] = id end
|
||||
end
|
||||
|
||||
-- populate editor keymap with configured combinations
|
||||
for _, map in ipairs(edcfg.keymap or {}) 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()
|
||||
|
||||
editor:SetFont(ide.font.eNormal)
|
||||
editor:StyleSetFont(wxstc.wxSTC_STYLE_DEFAULT, ide.font.eNormal)
|
||||
|
||||
editor:SetTabWidth(ide.config.editor.tabwidth or 2)
|
||||
editor:SetIndent(ide.config.editor.tabwidth or 2)
|
||||
editor:SetUseTabs(ide.config.editor.usetabs and true or false)
|
||||
editor:SetTabWidth(tonumber(edcfg.tabwidth) or 2)
|
||||
editor:SetIndent(tonumber(edcfg.tabwidth) or 2)
|
||||
editor:SetUseTabs(edcfg.usetabs and true or false)
|
||||
editor:SetIndentationGuides(true)
|
||||
editor:SetViewWhiteSpace(ide.config.editor.whitespace and true or false)
|
||||
editor:SetViewWhiteSpace(edcfg.whitespace and true or false)
|
||||
|
||||
if (ide.config.editor.usewrap) then
|
||||
if (edcfg.usewrap) then
|
||||
editor:SetWrapMode(wxstc.wxSTC_WRAP_WORD)
|
||||
editor:SetWrapStartIndent(0)
|
||||
editor:SetWrapVisualFlagsLocation(wxstc.wxSTC_WRAPVISUALFLAGLOC_END_BY_TEXT)
|
||||
if ide.wxver >= "2.9.5" then
|
||||
if edcfg.wrapflags then
|
||||
editor:SetWrapVisualFlags(tonumber(edcfg.wrapflags) or wxstc.wxSTC_WRAPVISUALFLAG_NONE)
|
||||
end
|
||||
if edcfg.wrapstartindent then
|
||||
editor:SetWrapStartIndent(tonumber(edcfg.wrapstartindent) or 0)
|
||||
end
|
||||
if edcfg.wrapindentmode then
|
||||
editor:SetWrapIndentMode(edcfg.wrapindentmode)
|
||||
end
|
||||
end
|
||||
else
|
||||
editor:SetScrollWidth(100) -- set default width
|
||||
editor:SetScrollWidthTracking(1) -- enable width auto-adjustment
|
||||
end
|
||||
|
||||
if (ide.config.editor.defaulteol == wxstc.wxSTC_EOL_CRLF
|
||||
or ide.config.editor.defaulteol == wxstc.wxSTC_EOL_LF) then
|
||||
editor:SetEOLMode(ide.config.editor.defaulteol)
|
||||
if edcfg.defaulteol == wxstc.wxSTC_EOL_CRLF
|
||||
or edcfg.defaulteol == wxstc.wxSTC_EOL_LF then
|
||||
editor:SetEOLMode(edcfg.defaulteol)
|
||||
-- else: keep wxStyledTextCtrl default behavior (CRLF on Windows, LF on Unix)
|
||||
end
|
||||
|
||||
editor:SetCaretLineVisible(ide.config.editor.caretline and 1 or 0)
|
||||
editor:SetCaretLineVisible(edcfg.caretline and true or false)
|
||||
|
||||
editor:SetVisiblePolicy(wxstc.wxSTC_VISIBLE_STRICT, 3)
|
||||
|
||||
editor:SetMarginWidth(margin.LINENUMBER, editor:TextWidth(DEFAULT_STYLE, "99999_"))
|
||||
editor:SetMarginType(margin.LINENUMBER, wxstc.wxSTC_MARGIN_NUMBER)
|
||||
editor:SetMarginMask(margin.LINENUMBER, 0)
|
||||
editor:SetMarginWidth(margin.LINENUMBER,
|
||||
editor:TextWidth(wxstc.wxSTC_STYLE_DEFAULT, linenummask))
|
||||
|
||||
editor:SetMarginWidth(margin.MARKER, 16)
|
||||
editor:SetMarginWidth(margin.MARKER, 18)
|
||||
editor:SetMarginType(margin.MARKER, wxstc.wxSTC_MARGIN_SYMBOL)
|
||||
editor:SetMarginMask(margin.MARKER, bit.bnot(wxstc.wxSTC_MASK_FOLDERS))
|
||||
editor:SetMarginSensitive(margin.MARKER, true)
|
||||
|
||||
editor:MarkerDefine(StylesGetMarker("currentline"))
|
||||
editor:MarkerDefine(StylesGetMarker("breakpoint"))
|
||||
editor:MarkerDefine(StylesGetMarker("bookmark"))
|
||||
|
||||
if ide.config.editor.fold then
|
||||
editor:SetMarginWidth(margin.FOLD, 16)
|
||||
if edcfg.fold then
|
||||
editor:SetMarginWidth(margin.FOLD, 18)
|
||||
editor:SetMarginType(margin.FOLD, wxstc.wxSTC_MARGIN_SYMBOL)
|
||||
editor:SetMarginMask(margin.FOLD, wxstc.wxSTC_MASK_FOLDERS)
|
||||
editor:SetMarginSensitive(margin.FOLD, true)
|
||||
end
|
||||
|
||||
editor:SetFoldFlags(wxstc.wxSTC_FOLDFLAG_LINEBEFORE_CONTRACTED +
|
||||
wxstc.wxSTC_FOLDFLAG_LINEAFTER_CONTRACTED)
|
||||
editor:SetFoldFlags(tonumber(edcfg.foldflags) or wxstc.wxSTC_FOLDFLAG_LINEAFTER_CONTRACTED)
|
||||
|
||||
-- allow multiple selection and multi-cursor editing if supported
|
||||
if ide.wxver >= "2.9.5" then
|
||||
-- allow multiple selection and multi-cursor editing if supported
|
||||
editor:SetMultipleSelection(1)
|
||||
editor:SetAdditionalCaretsBlink(1)
|
||||
editor:SetAdditionalSelectionTyping(1)
|
||||
-- allow extra ascent/descent
|
||||
editor:SetExtraAscent(tonumber(edcfg.extraascent) or 0)
|
||||
editor:SetExtraDescent(tonumber(edcfg.extradescent) or 0)
|
||||
end
|
||||
|
||||
do
|
||||
local fg, bg = wx.wxWHITE, wx.wxColour(128, 128, 128)
|
||||
editor:MarkerDefine(wxstc.wxSTC_MARKNUM_FOLDEROPEN, wxstc.wxSTC_MARK_BOXMINUS, fg, bg)
|
||||
editor:MarkerDefine(wxstc.wxSTC_MARKNUM_FOLDER, wxstc.wxSTC_MARK_BOXPLUS, fg, bg)
|
||||
editor:MarkerDefine(wxstc.wxSTC_MARKNUM_FOLDERSUB, wxstc.wxSTC_MARK_VLINE, fg, bg)
|
||||
editor:MarkerDefine(wxstc.wxSTC_MARKNUM_FOLDERTAIL, wxstc.wxSTC_MARK_LCORNER, fg, bg)
|
||||
editor:MarkerDefine(wxstc.wxSTC_MARKNUM_FOLDEREND, wxstc.wxSTC_MARK_BOXPLUSCONNECTED, fg, bg)
|
||||
editor:MarkerDefine(wxstc.wxSTC_MARKNUM_FOLDEROPENMID, wxstc.wxSTC_MARK_BOXMINUSCONNECTED, fg, bg)
|
||||
editor:MarkerDefine(wxstc.wxSTC_MARKNUM_FOLDERMIDTAIL, wxstc.wxSTC_MARK_TCORNER, fg, bg)
|
||||
local foldtype = foldtypes[edcfg.foldtype] or foldtypes.box
|
||||
local foldmarkers = foldtypes[0]
|
||||
for m = 1, #foldmarkers do
|
||||
editor:MarkerDefine(foldmarkers[m], foldtype[m] or wxstc.wxSTC_MARK_EMPTY, fg, bg)
|
||||
end
|
||||
bg:delete()
|
||||
end
|
||||
|
||||
if ide.config.editor.calltipdelay and ide.config.editor.calltipdelay > 0 then
|
||||
editor:SetMouseDwellTime(ide.config.editor.calltipdelay)
|
||||
if edcfg.calltipdelay and edcfg.calltipdelay > 0 then
|
||||
editor:SetMouseDwellTime(edcfg.calltipdelay)
|
||||
end
|
||||
|
||||
editor:AutoCompSetIgnoreCase(ide.config.acandtip.ignorecase)
|
||||
@@ -680,6 +774,11 @@ function CreateEditor()
|
||||
editor:AutoCompStops([[ \n\t=-+():.,;*/!"'$%&~'#°^@?´`<>][|}{]])
|
||||
end
|
||||
|
||||
function editor:GotoPosEnforcePolicy(pos)
|
||||
self:GotoPos(pos)
|
||||
self:EnsureVisibleEnforcePolicy(self:LineFromPosition(pos))
|
||||
end
|
||||
|
||||
-- GotoPos should work by itself, but it doesn't (wx 2.9.5).
|
||||
-- This is likely because the editor window hasn't been refreshed yet,
|
||||
-- so its LinesOnScreen method returns 0/-1, which skews the calculations.
|
||||
@@ -696,26 +795,28 @@ function CreateEditor()
|
||||
if ide.osname ~= 'Macintosh' then self:GotoPos(pos) end
|
||||
else
|
||||
redolater = nil
|
||||
self:GotoPos(pos)
|
||||
self:GotoPosEnforcePolicy(pos)
|
||||
end
|
||||
elseif not badtime and redolater then
|
||||
-- reset the left margin first to make sure that the position
|
||||
-- is set "from the left" to get the best content displayed.
|
||||
self:SetXOffset(0)
|
||||
self:GotoPos(redolater)
|
||||
self:GotoPosEnforcePolicy(redolater)
|
||||
redolater = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function editor:SetupKeywords(...) return SetupKeywords(self, ...) end
|
||||
|
||||
editor.ev = {}
|
||||
editor:Connect(wxstc.wxEVT_STC_MARGINCLICK,
|
||||
function (event)
|
||||
local line = editor:LineFromPosition(event:GetPosition())
|
||||
local margin = event:GetMargin()
|
||||
if margin == 1 then
|
||||
local marginno = event:GetMargin()
|
||||
if marginno == margin.MARKER then
|
||||
DebuggerToggleBreakpoint(editor, line)
|
||||
elseif margin == 2 then
|
||||
elseif marginno == margin.FOLD then
|
||||
if wx.wxGetKeyState(wx.WXK_SHIFT) and wx.wxGetKeyState(wx.WXK_CONTROL) then
|
||||
FoldSome()
|
||||
else
|
||||
@@ -733,31 +834,42 @@ function CreateEditor()
|
||||
editor.assignscache = false
|
||||
end
|
||||
local evtype = event:GetModificationType()
|
||||
if (bit.band(evtype,wxstc.wxSTC_MOD_INSERTTEXT) ~= 0) then
|
||||
local inserted = bit.band(evtype, wxstc.wxSTC_MOD_INSERTTEXT) ~= 0
|
||||
local deleted = bit.band(evtype, wxstc.wxSTC_MOD_DELETETEXT) ~= 0
|
||||
if (inserted or deleted) then
|
||||
SetAutoRecoveryMark()
|
||||
table.insert(editor.ev,{event:GetPosition(),event:GetLinesAdded()})
|
||||
DynamicWordsAdd("post",editor,nil,editor:LineFromPosition(event:GetPosition()),event:GetLinesAdded())
|
||||
|
||||
local firstLine = editor:LineFromPosition(event:GetPosition())
|
||||
local linesChanged = inserted and event:GetLinesAdded() or 0
|
||||
table.insert(editor.ev, {event:GetPosition(), linesChanged})
|
||||
DynamicWordsAdd(editor, nil, firstLine, linesChanged)
|
||||
end
|
||||
if (bit.band(evtype,wxstc.wxSTC_MOD_DELETETEXT) ~= 0) then
|
||||
SetAutoRecoveryMark()
|
||||
table.insert(editor.ev,{event:GetPosition(),0})
|
||||
DynamicWordsAdd("post",editor,nil,editor:LineFromPosition(event:GetPosition()),0)
|
||||
|
||||
local beforeInserted = bit.band(evtype,wxstc.wxSTC_MOD_BEFOREINSERT) ~= 0
|
||||
local beforeDeleted = bit.band(evtype,wxstc.wxSTC_MOD_BEFOREDELETE) ~= 0
|
||||
|
||||
if (beforeInserted or beforeDeleted) then
|
||||
-- unfold the current line being changed if folded
|
||||
local firstLine = editor:LineFromPosition(event:GetPosition())
|
||||
if not editor:GetFoldExpanded(firstLine) then editor:ToggleFold(firstLine) end
|
||||
end
|
||||
|
||||
if ide.config.acandtip.nodynwords then return end
|
||||
-- only required to track changes
|
||||
if (bit.band(evtype,wxstc.wxSTC_MOD_BEFOREDELETE) ~= 0) then
|
||||
local _, numlines = event:GetText():gsub("\r?\n","%1")
|
||||
DynamicWordsRem("pre",editor,nil,editor:LineFromPosition(event:GetPosition()), numlines)
|
||||
|
||||
if beforeDeleted then
|
||||
local pos = event:GetPosition()
|
||||
local text = editor:GetTextRange(pos, pos+event:GetLength())
|
||||
local _, numlines = text:gsub("\r?\n","%1")
|
||||
DynamicWordsRem(editor,nil,editor:LineFromPosition(pos), numlines)
|
||||
end
|
||||
if (bit.band(evtype,wxstc.wxSTC_MOD_BEFOREINSERT) ~= 0) then
|
||||
DynamicWordsRem("pre",editor,nil,editor:LineFromPosition(event:GetPosition()), 0)
|
||||
if beforeInserted then
|
||||
DynamicWordsRem(editor,nil,editor:LineFromPosition(event:GetPosition()), 0)
|
||||
end
|
||||
end)
|
||||
|
||||
editor:Connect(wxstc.wxEVT_STC_CHARADDED,
|
||||
function (event)
|
||||
-- auto-indent
|
||||
local LF = string.byte("\n")
|
||||
local ch = event:GetKey()
|
||||
local pos = editor:GetCurrentPos()
|
||||
@@ -770,22 +882,27 @@ function CreateEditor()
|
||||
if PackageEventHandle("onEditorCharAdded", editor, event) == false then
|
||||
-- this event has already been handled
|
||||
elseif (ch == LF) then
|
||||
-- auto-indent
|
||||
if (line > 0) then
|
||||
local indent = editor:GetLineIndentation(line - 1)
|
||||
local linedone = editor:GetLine(line - 1)
|
||||
|
||||
-- if the indentation is 0 and the current line is not empty
|
||||
-- then take indentation from the current line (instead of the
|
||||
-- previous one). This may happen when CR is hit at the beginning
|
||||
-- of a line (rather than at the end).
|
||||
if indent == 0 and not linetx:match("^[\010\013]*$") then
|
||||
-- if the indentation is 0 and the current line is not empty,
|
||||
-- but the previous line is empty, then take indentation from the
|
||||
-- current line (instead of the previous one). This may happen when
|
||||
-- CR is hit at the beginning of a line (rather than at the end).
|
||||
if indent == 0 and not linetx:match("^[\010\013]*$")
|
||||
and linedone:match("^[\010\013]*$") then
|
||||
indent = editor:GetLineIndentation(line)
|
||||
end
|
||||
|
||||
local ut = editor:GetUseTabs()
|
||||
local tw = ut and editor:GetTabWidth() or editor:GetIndent()
|
||||
local style = bit.band(editor:GetStyleAt(editor:PositionFromLine(line-1)), 31)
|
||||
|
||||
if ide.config.editor.smartindent
|
||||
if edcfg.smartindent
|
||||
-- don't apply smartindent to multi-line comments or strings
|
||||
and not (editor.spec.iscomment[style] or editor.spec.isstring[style])
|
||||
and editor.spec.isdecindent and editor.spec.isincindent then
|
||||
local closed, blockend = editor.spec.isdecindent(linedone)
|
||||
local opened = editor.spec.isincindent(linedone)
|
||||
@@ -811,14 +928,14 @@ 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
|
||||
local trigger = linetxtopos:match("["..editor.spec.sep.."%w_]+$")
|
||||
if (trigger and (#trigger > 1 or trigger:match("["..editor.spec.sep.."]"))) then
|
||||
editor.autocomplete = true
|
||||
end
|
||||
-- make sure .autocomplete is never `nil` or editor.autocomplete fails
|
||||
editor.autocomplete = trigger and (#trigger > 1 or trigger:match("["..editor.spec.sep.."]"))
|
||||
and true or false
|
||||
end
|
||||
end)
|
||||
|
||||
@@ -865,6 +982,10 @@ function CreateEditor()
|
||||
|
||||
editor:Connect(wxstc.wxEVT_STC_USERLISTSELECTION,
|
||||
function (event)
|
||||
if PackageEventHandle("onEditorUserlistSelection", editor, event) == false then
|
||||
return
|
||||
end
|
||||
|
||||
if ide.wxver >= "2.9.5" and editor:GetSelections() > 1 then
|
||||
local text = event:GetText()
|
||||
-- capture all positions as the selection may change
|
||||
@@ -917,12 +1038,26 @@ function CreateEditor()
|
||||
-- where refresh of R/W and R/O status in the status bar is delayed.
|
||||
|
||||
editor:Connect(wxstc.wxEVT_STC_PAINTED,
|
||||
function ()
|
||||
if ide.osname == 'Windows' then updateStatusText(editor) end
|
||||
function (event)
|
||||
PackageEventHandle("onEditorPainted", editor, event)
|
||||
|
||||
if ide.osname == 'Windows' then
|
||||
updateStatusText(editor)
|
||||
|
||||
if edcfg.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,
|
||||
function ()
|
||||
function (event)
|
||||
PackageEventHandle("onEditorUpdateUI", editor, event)
|
||||
|
||||
if ide.osname ~= 'Windows' then updateStatusText(editor) end
|
||||
|
||||
editor:GotoPosDelayed()
|
||||
@@ -942,7 +1077,10 @@ function CreateEditor()
|
||||
firstvisible)
|
||||
MarkupStyle(editor,minupdated or firstline,lastline)
|
||||
editor.ev = {}
|
||||
end)
|
||||
|
||||
editor:Connect(wx.wxEVT_IDLE,
|
||||
function (event)
|
||||
-- show auto-complete if needed
|
||||
if editor.autocomplete then
|
||||
EditorAutoComplete(editor)
|
||||
@@ -974,7 +1112,7 @@ function CreateEditor()
|
||||
event:Skip()
|
||||
end)
|
||||
|
||||
if ide.config.editor.nomousezoom then
|
||||
if edcfg.nomousezoom then
|
||||
-- disable zoom using mouse wheel as it triggers zooming when scrolling
|
||||
-- on OSX with kinetic scroll and then pressing CMD.
|
||||
editor:Connect(wx.wxEVT_MOUSEWHEEL,
|
||||
@@ -1026,8 +1164,18 @@ function CreateEditor()
|
||||
and (mod == wx.wxMOD_NONE) then
|
||||
-- Delete and Backspace behave the same way for selected text
|
||||
if #(editor:GetSelectedText()) > 0 then
|
||||
editor:SetTargetStart(editor:GetSelectionStart())
|
||||
editor:SetTargetEnd(editor:GetSelectionEnd())
|
||||
local length = editor:GetLength()
|
||||
local selections = ide.wxver >= "2.9.5" and editor:GetSelections() or 1
|
||||
editor:Clear() -- remove selected fragments
|
||||
|
||||
-- check if the modification has failed, which may happen
|
||||
-- if there is "invisible" text in the selected fragment.
|
||||
-- if there is only one selection, then delete manually.
|
||||
if length == editor:GetLength() and selections == 1 then
|
||||
editor:SetTargetStart(editor:GetSelectionStart())
|
||||
editor:SetTargetEnd(editor:GetSelectionEnd())
|
||||
editor:ReplaceTarget("")
|
||||
end
|
||||
else
|
||||
local pos = editor:GetCurrentPos()
|
||||
if keycode == wx.WXK_BACK then
|
||||
@@ -1047,10 +1195,16 @@ function CreateEditor()
|
||||
|
||||
editor:SetTargetStart(pos)
|
||||
editor:SetTargetEnd(pos+1)
|
||||
editor:ReplaceTarget("")
|
||||
end
|
||||
editor:ReplaceTarget("")
|
||||
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 (keycode == wx.WXK_DELETE and mod == wx.wxMOD_SHIFT)
|
||||
or (keycode == wx.WXK_INSERT and mod == wx.wxMOD_CONTROL) then
|
||||
ide.frame:AddPendingEvent(wx.wxCommandEvent(
|
||||
wx.wxEVT_COMMAND_MENU_SELECTED, keycode == wx.WXK_INSERT and ID_COPY or ID_CUT))
|
||||
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(
|
||||
@@ -1066,7 +1220,7 @@ function CreateEditor()
|
||||
local function selectAllInstances(instances, name, curpos)
|
||||
local this
|
||||
local idx = 0
|
||||
for i, pos in pairs(instances) do
|
||||
for _, pos in pairs(instances) do
|
||||
pos = pos - 1 -- positions are 0-based in Scintilla
|
||||
if idx == 0 then
|
||||
-- clear selections first as there seems to be a bug (Scintilla 3.2.3)
|
||||
@@ -1102,7 +1256,16 @@ function CreateEditor()
|
||||
|
||||
editor:Connect(wxstc.wxEVT_STC_ZOOM,
|
||||
function(event)
|
||||
editor:SetMarginWidth(margin.LINENUMBER, editor:TextWidth(DEFAULT_STYLE, "99999_"))
|
||||
editor:SetMarginWidth(margin.LINENUMBER,
|
||||
editor:TextWidth(wxstc.wxSTC_STYLE_DEFAULT, linenummask))
|
||||
-- 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 _, 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)
|
||||
|
||||
@@ -1118,6 +1281,7 @@ function CreateEditor()
|
||||
or (" (%d)"):format(#instances+(instances[0] and 1 or 0))
|
||||
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 selections = ide.wxver >= "2.9.5" and editor:GetSelections() or 1
|
||||
|
||||
local menu = wx.wxMenu {
|
||||
{ ID_UNDO, TR("&Undo") },
|
||||
@@ -1130,6 +1294,7 @@ function CreateEditor()
|
||||
{ },
|
||||
{ ID_GOTODEFINITION, TR("Go To Definition")..def },
|
||||
{ ID_RENAMEALLINSTANCES, TR("Rename All Instances")..occurrences },
|
||||
{ ID_REPLACEALLSELECTIONS, TR("Replace All Selections") },
|
||||
{ },
|
||||
{ ID_QUICKADDWATCH, TR("Add Watch Expression") },
|
||||
{ ID_QUICKEVAL, TR("Evaluate In Console") },
|
||||
@@ -1137,7 +1302,9 @@ function CreateEditor()
|
||||
}
|
||||
|
||||
menu:Enable(ID_GOTODEFINITION, instances and instances[0])
|
||||
menu:Enable(ID_RENAMEALLINSTANCES, instances and (instances[0] or #instances > 0))
|
||||
menu:Enable(ID_RENAMEALLINSTANCES, instances and (instances[0] or #instances > 0)
|
||||
or editor:GetSelectionStart() ~= editor:GetSelectionEnd())
|
||||
menu:Enable(ID_REPLACEALLSELECTIONS, selections > 1)
|
||||
menu:Enable(ID_QUICKADDWATCH, value ~= nil)
|
||||
menu:Enable(ID_QUICKEVAL, value ~= nil)
|
||||
|
||||
@@ -1168,12 +1335,49 @@ function CreateEditor()
|
||||
editor:Connect(ID_RENAMEALLINSTANCES, wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
function(event)
|
||||
if value and pos then
|
||||
if not (instances and (instances[0] or #instances > 0)) then
|
||||
-- if multiple instances (of a variable) are not detected,
|
||||
-- then simply find all instances of (selected) `value`
|
||||
instances = {}
|
||||
local length, pos = editor:GetLength(), 0
|
||||
while true do
|
||||
editor:SetTargetStart(pos)
|
||||
editor:SetTargetEnd(length)
|
||||
pos = editor:SearchInTarget(value)
|
||||
if pos == -1 then break end
|
||||
table.insert(instances, pos+1)
|
||||
pos = pos + #value
|
||||
end
|
||||
end
|
||||
selectAllInstances(instances, value, pos)
|
||||
end
|
||||
end)
|
||||
|
||||
editor:Connect(ID_REPLACEALLSELECTIONS, wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
function(event)
|
||||
local main = editor:GetMainSelection()
|
||||
local text = wx.wxGetTextFromUser(
|
||||
TR("Enter replacement text"),
|
||||
TR("Replace All Selections"),
|
||||
editor:GetTextRange(editor:GetSelectionNStart(main), editor:GetSelectionNEnd(main))
|
||||
)
|
||||
if not text or text == "" then return end
|
||||
|
||||
editor:BeginUndoAction()
|
||||
for s = 0, editor:GetSelections()-1 do
|
||||
local selst, selend = editor:GetSelectionNStart(s), editor:GetSelectionNEnd(s)
|
||||
editor:SetTargetStart(selst)
|
||||
editor:SetTargetEnd(selend)
|
||||
editor:ReplaceTarget(text)
|
||||
editor:SetSelectionNStart(s, selst)
|
||||
editor:SetSelectionNEnd(s, selst+#text)
|
||||
end
|
||||
editor:EndUndoAction()
|
||||
editor:SetMainSelection(main)
|
||||
end)
|
||||
|
||||
editor:Connect(ID_QUICKADDWATCH, wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
function(event) DebuggerAddWatch(value) end)
|
||||
function(event) ide:AddWatch(value) end)
|
||||
|
||||
editor:Connect(ID_QUICKEVAL, wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
function(event) ShellExecuteCode(value) end)
|
||||
@@ -1187,6 +1391,7 @@ end
|
||||
-- ----------------------------------------------------------------------------
|
||||
-- Add an editor to the notebook
|
||||
function AddEditor(editor, name)
|
||||
assert(notebook:GetPageIndex(editor) == -1, "Editor being added is not in the notebook: failed")
|
||||
if notebook:AddPage(editor, name, true) then
|
||||
local id = editor:GetId()
|
||||
local document = setmetatable({}, ide.proto.Document)
|
||||
@@ -1240,25 +1445,6 @@ function SetupKeywords(editor, ext, forcespec, styles, font, fontitalic)
|
||||
end
|
||||
end
|
||||
|
||||
if (spec.api == "lua") then
|
||||
-- Get the items in the global "wx" table for autocompletion
|
||||
if not wxkeywords then
|
||||
local keyword_table = {}
|
||||
for index in pairs(wx) do
|
||||
table.insert(keyword_table, "wx."..index.." ")
|
||||
end
|
||||
|
||||
for index in pairs(wxstc) do
|
||||
table.insert(keyword_table, "wxstc."..index.." ")
|
||||
end
|
||||
|
||||
table.sort(keyword_table)
|
||||
wxkeywords = table.concat(keyword_table)
|
||||
end
|
||||
local offset = spec.keywords and #spec.keywords or 5
|
||||
editor:SetKeyWords(offset, wxkeywords)
|
||||
end
|
||||
|
||||
editor.api = GetApi(spec.apitype or "none")
|
||||
editor.spec = spec
|
||||
else
|
||||
@@ -1271,10 +1457,10 @@ function SetupKeywords(editor, ext, forcespec, styles, font, fontitalic)
|
||||
|
||||
-- need to set folding property after lexer is set, otherwise
|
||||
-- the folds are not shown (wxwidgets 2.9.5)
|
||||
if ide.config.editor.fold then
|
||||
if edcfg.fold then
|
||||
editor:SetProperty("fold", "1")
|
||||
editor:SetProperty("fold.html", "1")
|
||||
editor:SetProperty("fold.compact", ide.config.editor.foldcompact and "1" or "0")
|
||||
editor:SetProperty("fold.compact", edcfg.foldcompact and "1" or "0")
|
||||
editor:SetProperty("fold.comment", "1")
|
||||
end
|
||||
|
||||
@@ -1346,5 +1532,6 @@ funclist:Connect(wx.wxEVT_COMMAND_CHOICE_SELECTED,
|
||||
editor:GotoLine(l)
|
||||
editor:SetFocus()
|
||||
editor:SetSTCFocus(true)
|
||||
editor:EnsureVisibleEnforcePolicy(l)
|
||||
end
|
||||
end)
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
-- Copyright 2011-14 Paul Kulchenko, ZeroBrane LLC
|
||||
-- authors: Luxinia Dev (Eike Decker & Christoph Kubisch)
|
||||
---------------------------------------------------------
|
||||
|
||||
local ide = ide
|
||||
--
|
||||
-- filetree, treectrl for drive & project
|
||||
@@ -8,8 +10,8 @@ local ide = ide
|
||||
ide.filetree = {
|
||||
projdir = "",
|
||||
projdirlist = {},
|
||||
projdirmap = {},
|
||||
projdirpartmap = {},
|
||||
projtree = nil,
|
||||
}
|
||||
local filetree = ide.filetree
|
||||
|
||||
@@ -20,18 +22,15 @@ local q = EscapeMagic
|
||||
-- generic tree
|
||||
-- ------------
|
||||
|
||||
local IMG_DIRECTORY, IMG_FILE_KNOWN, IMG_FILE_OTHER = 0, 1, 2
|
||||
local image = { DIRECTORY = 0, FILEKNOWN = 1, FILEOTHER = 2 }
|
||||
|
||||
do
|
||||
local getBitmap = (ide.app.createbitmap or wx.wxArtProvider.GetBitmap)
|
||||
local size = wx.wxSize(16, 16)
|
||||
filetree.imglist = wx.wxImageList(16,16)
|
||||
-- 0 = directory
|
||||
filetree.imglist:Add(getBitmap(wx.wxART_FOLDER, wx.wxART_OTHER, size))
|
||||
-- 1 = file known spec
|
||||
filetree.imglist:Add(getBitmap(wx.wxART_HELP_PAGE, wx.wxART_OTHER, size))
|
||||
-- 2 = file other
|
||||
filetree.imglist:Add(getBitmap(wx.wxART_NORMAL_FILE, wx.wxART_OTHER, size))
|
||||
filetree.imglist:Add(getBitmap("FOLDER", "OTHER", size)) -- 0 = directory
|
||||
filetree.imglist:Add(getBitmap("HELP-PAGE", "OTHER", size)) -- 1 = file known spec
|
||||
filetree.imglist:Add(getBitmap("NORMAL-FILE", "OTHER", size)) -- 2 = file other
|
||||
end
|
||||
|
||||
local function treeAddDir(tree,parent_id,rootdir)
|
||||
@@ -48,13 +47,14 @@ local function treeAddDir(tree,parent_id,rootdir)
|
||||
for _, file in ipairs(FileSysGetRecursive(rootdir)) do
|
||||
local name, dir = file:match("([^"..pathsep.."]+)("..pathsep.."?)$")
|
||||
local known = GetSpec(GetFileExt(name))
|
||||
local icon = #dir>0 and IMG_DIRECTORY or known and IMG_FILE_KNOWN or IMG_FILE_OTHER
|
||||
local icon = #dir>0 and image.DIRECTORY or known and image.FILEKNOWN or image.FILEOTHER
|
||||
local item = items[name .. icon]
|
||||
if item then -- existing item
|
||||
-- keep deleting items until we find item
|
||||
while true do
|
||||
local next = curr and tree:GetNextSibling(curr)
|
||||
or tree:GetFirstChild(parent_id)
|
||||
local next = (curr
|
||||
and tree:GetNextSibling(curr)
|
||||
or tree:GetFirstChild(parent_id))
|
||||
if not next:IsOk() or name == tree:GetItemText(next) then
|
||||
curr = next
|
||||
break
|
||||
@@ -62,25 +62,29 @@ local function treeAddDir(tree,parent_id,rootdir)
|
||||
tree:Delete(next)
|
||||
end
|
||||
else -- new item
|
||||
curr = curr and tree:InsertItem(parent_id, curr, name, icon)
|
||||
or tree:PrependItem(parent_id, name, icon)
|
||||
if #dir>0 then tree:SetItemHasChildren(curr, FileSysHasContent(file)) end
|
||||
curr = (curr
|
||||
and tree:InsertItem(parent_id, curr, name, icon)
|
||||
or tree:PrependItem(parent_id, name, icon))
|
||||
if #dir>0 then tree:SetItemHasChildren(curr, FileDirHasContent(file)) end
|
||||
end
|
||||
if curr:IsOk() then cache[iscaseinsensitive and name:lower() or name] = curr end
|
||||
end
|
||||
|
||||
-- delete any leftovers (something that exists in the tree, but not on disk)
|
||||
while true do
|
||||
local next = curr and tree:GetNextSibling(curr)
|
||||
or tree:GetFirstChild(parent_id)
|
||||
local next = (curr
|
||||
and tree:GetNextSibling(curr)
|
||||
or tree:GetFirstChild(parent_id))
|
||||
if not next:IsOk() then break end
|
||||
tree:Delete(next)
|
||||
end
|
||||
|
||||
-- cache the mapping from names to tree items
|
||||
local data = wx.wxLuaTreeItemData()
|
||||
data:SetData(cache)
|
||||
tree:SetItemData(parent_id, data)
|
||||
if ide.wxver >= "2.9.5" then
|
||||
local data = wx.wxLuaTreeItemData()
|
||||
data:SetData(cache)
|
||||
tree:SetItemData(parent_id, data)
|
||||
end
|
||||
|
||||
tree:SetItemHasChildren(parent_id,
|
||||
tree:GetChildrenCount(parent_id, false) > 0)
|
||||
@@ -90,7 +94,7 @@ local function treeSetRoot(tree,rootdir)
|
||||
tree:DeleteAllItems()
|
||||
if (not wx.wxDirExists(rootdir)) then return end
|
||||
|
||||
local root_id = tree:AddRoot(rootdir, IMG_DIRECTORY)
|
||||
local root_id = tree:AddRoot(rootdir, image.DIRECTORY)
|
||||
tree:SetItemHasChildren(root_id, true) -- make sure that the item can expand
|
||||
tree:Expand(root_id) -- this will also populate the tree
|
||||
end
|
||||
@@ -134,7 +138,19 @@ local function findItem(tree, match)
|
||||
end
|
||||
|
||||
local function treeSetConnectorsAndIcons(tree)
|
||||
tree:SetImageList(filetree.imglist)
|
||||
tree:AssignImageList(filetree.imglist)
|
||||
|
||||
local function isIt(item, imgtype) return tree:GetItemImage(item) == imgtype end
|
||||
|
||||
function tree:IsDirectory(item_id) return isIt(item_id, image.DIRECTORY) end
|
||||
function tree:IsFileKnown(item_id) return isIt(item_id, image.FILEKNOWN) end
|
||||
function tree:IsFileOther(item_id) return isIt(item_id, image.FILEOTHER) end
|
||||
function tree:IsRoot(item_id) return not tree:GetItemParent(item_id):IsOk() end
|
||||
|
||||
function tree:FindItem(match)
|
||||
return findItem(self, wx.wxIsAbsolutePath(match) and match
|
||||
or MergeFullPath(ide:GetProject(), match))
|
||||
end
|
||||
|
||||
function tree:GetItemFullName(item_id)
|
||||
local tree = self
|
||||
@@ -166,9 +182,27 @@ local function treeSetConnectorsAndIcons(tree)
|
||||
tree:SetEvtHandlerEnabled(true)
|
||||
end
|
||||
|
||||
function tree:ActivateItem(item_id)
|
||||
local name = tree:GetItemFullName(item_id)
|
||||
|
||||
local event = wx.wxTreeEvent(wx.wxEVT_COMMAND_TREE_ITEM_ACTIVATED, item_id:GetValue())
|
||||
if PackageEventHandle("onFiletreeActivate", tree, event, item_id) == false then
|
||||
return
|
||||
end
|
||||
|
||||
-- refresh the folder
|
||||
if (tree:IsDirectory(item_id)) then
|
||||
if wx.wxDirExists(name) then treeAddDir(tree,item_id,name)
|
||||
else refreshAncestors(tree:GetItemParent(item_id)) end -- stale content
|
||||
else -- open file
|
||||
if wx.wxFileExists(name) then LoadFile(name,nil,true)
|
||||
else refreshAncestors(tree:GetItemParent(item_id)) end -- stale content
|
||||
end
|
||||
end
|
||||
|
||||
local empty = ""
|
||||
local function renameItem(itemsrc, target)
|
||||
local isdir = tree:GetItemImage(itemsrc) == IMG_DIRECTORY
|
||||
local isdir = tree:GetItemImage(itemsrc) == image.DIRECTORY
|
||||
local isnew = tree:GetItemText(itemsrc) == empty
|
||||
local source = tree:GetItemFullName(itemsrc)
|
||||
local fn = wx.wxFileName(target)
|
||||
@@ -177,9 +211,9 @@ local function treeSetConnectorsAndIcons(tree)
|
||||
|
||||
local docs = {}
|
||||
if not isnew then -- find if source is already opened in the editor
|
||||
docs = isdir
|
||||
docs = (isdir
|
||||
and ide:FindDocumentsByPartialPath(source)
|
||||
or {ide:FindDocument(source)}
|
||||
or {ide:FindDocument(source)})
|
||||
for _, doc in ipairs(docs) do
|
||||
if SaveModifiedDialog(doc.editor, true) == wx.wxID_CANCEL then return end
|
||||
end
|
||||
@@ -220,7 +254,7 @@ local function treeSetConnectorsAndIcons(tree)
|
||||
LoadFile(fullpath:gsub(q(source), target), doc.editor)
|
||||
end
|
||||
else -- refresh the tree and select the new item
|
||||
local itemdst = findItem(tree, target)
|
||||
local itemdst = tree:FindItem(target)
|
||||
if itemdst then
|
||||
refreshAncestors(tree:GetItemParent(itemdst))
|
||||
tree:SelectItem(itemdst)
|
||||
@@ -231,17 +265,20 @@ local function treeSetConnectorsAndIcons(tree)
|
||||
return true
|
||||
end
|
||||
local function deleteItem(item_id)
|
||||
local isdir = tree:GetItemImage(item_id) == IMG_DIRECTORY
|
||||
local isdir = tree:GetItemImage(item_id) == image.DIRECTORY
|
||||
local source = tree:GetItemFullName(item_id)
|
||||
|
||||
if isdir and FileSysHasContent(source..pathsep) then return false end
|
||||
if isdir and FileDirHasContent(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)
|
||||
if not wx.wxRmdir(source) then
|
||||
ReportError(TR("Unable to delete directory '%s': %s")
|
||||
:format(source, wx.wxSysErrorMsg()))
|
||||
end
|
||||
else
|
||||
local doc = ide:FindDocument(source)
|
||||
if doc then ClosePage(doc.index) end
|
||||
@@ -261,54 +298,102 @@ local function treeSetConnectorsAndIcons(tree)
|
||||
end)
|
||||
tree:Connect(wx.wxEVT_COMMAND_TREE_ITEM_ACTIVATED,
|
||||
function (event)
|
||||
local item_id = event:GetItem()
|
||||
local name = tree:GetItemFullName(item_id)
|
||||
-- refresh the folder
|
||||
if (tree:GetItemImage(item_id) == IMG_DIRECTORY) then
|
||||
if wx.wxDirExists(name) then treeAddDir(tree,item_id,name)
|
||||
else refreshAncestors(tree:GetItemParent(item_id)) end -- stale content
|
||||
else -- open file
|
||||
if wx.wxFileExists(name) then LoadFile(name,nil,true)
|
||||
else refreshAncestors(tree:GetItemParent(item_id)) end -- stale content
|
||||
tree:ActivateItem(event:GetItem())
|
||||
end)
|
||||
|
||||
-- handle context menu
|
||||
local function addItem(item_id, name, img)
|
||||
local isdir = tree:GetItemImage(item_id) == image.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, img)
|
||||
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
|
||||
|
||||
tree:Connect(ID_NEWFILE, wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
function()
|
||||
tree:EditLabel(addItem(tree:GetSelection(), empty, image.FILEOTHER))
|
||||
end)
|
||||
tree:Connect(ID_NEWDIRECTORY, wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
function()
|
||||
tree:EditLabel(addItem(tree:GetSelection(), empty, image.DIRECTORY))
|
||||
end)
|
||||
tree:Connect(ID_RENAMEFILE, wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
function() tree:EditLabel(tree:GetSelection()) end)
|
||||
tree:Connect(ID_DELETEFILE, wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
function() deleteItem(tree:GetSelection()) end)
|
||||
tree:Connect(ID_COPYFULLPATH, wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
function()
|
||||
local tdo = wx.wxTextDataObject(tree:GetItemFullName(tree:GetSelection()))
|
||||
if wx.wxClipboard:Get():Open() then
|
||||
wx.wxClipboard:Get():SetData(tdo)
|
||||
wx.wxClipboard:Get():Close()
|
||||
end
|
||||
end)
|
||||
-- handle context menu
|
||||
tree:Connect(ID_OPENEXTENSION, wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
function()
|
||||
local fname = tree:GetItemFullName(tree:GetSelection())
|
||||
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(tree:GetSelection())) end)
|
||||
|
||||
tree:Connect(wx.wxEVT_COMMAND_TREE_ITEM_MENU,
|
||||
function (event)
|
||||
local item_id = event:GetItem()
|
||||
tree:SelectItem(item_id)
|
||||
|
||||
local renamelabel = (tree:IsRoot(item_id)
|
||||
and TR("&Edit Project Directory")
|
||||
or TR("&Rename"))
|
||||
local menu = wx.wxMenu {
|
||||
{ ID_NEWFILE, TR("New &File") },
|
||||
{ ID_NEWDIRECTORY, TR("&New Directory") },
|
||||
{ },
|
||||
{ ID_RENAMEFILE, TR("&Rename")..KSC(ID_RENAMEFILE) },
|
||||
{ ID_RENAMEFILE, renamelabel..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
|
||||
local projectdirectorymenu = wx.wxMenu {
|
||||
{ },
|
||||
{ID_PROJECTDIRCHOOSE, TR("Choose...")..KSC(ID_PROJECTDIRCHOOSE), TR("Choose a project directory")},
|
||||
}
|
||||
local projectdirectory = wx.wxMenuItem(menu, ID_PROJECTDIR,
|
||||
TR("Project Directory"), TR("Set the project directory to be used"),
|
||||
wx.wxITEM_NORMAL, projectdirectorymenu)
|
||||
menu:Insert(6, projectdirectory)
|
||||
FileTreeProjectListUpdate(projectdirectorymenu, 0)
|
||||
|
||||
-- disable Delete on non-empty directories
|
||||
local isdir = tree:GetItemImage(item_id) == IMG_DIRECTORY
|
||||
local isdir = tree:GetItemImage(item_id) == image.DIRECTORY
|
||||
if isdir then
|
||||
local source = tree:GetItemFullName(item_id)
|
||||
menu:Enable(ID_DELETEFILE, not FileSysHasContent(source..pathsep))
|
||||
menu:Enable(ID_DELETEFILE, not FileDirHasContent(source..pathsep))
|
||||
menu:Enable(ID_OPENEXTENSION, false)
|
||||
else
|
||||
local fname = tree:GetItemText(item_id)
|
||||
@@ -317,71 +402,53 @@ local function treeSetConnectorsAndIcons(tree)
|
||||
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)
|
||||
|
||||
PackageEventHandle("onMenuFiletree", menu, tree, event)
|
||||
|
||||
tree:PopupMenu(menu)
|
||||
end)
|
||||
|
||||
tree:Connect(wx.wxEVT_RIGHT_DOWN,
|
||||
function (event)
|
||||
local item_id = tree:HitTest(event:GetPosition())
|
||||
if PackageEventHandle("onFiletreeRDown", tree, event, item_id) == false then
|
||||
return
|
||||
end
|
||||
event:Skip()
|
||||
end)
|
||||
|
||||
-- toggle a folder on a single click
|
||||
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 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)
|
||||
|
||||
if PackageEventHandle("onFiletreeLDown", tree, event, item_id) == false then
|
||||
return
|
||||
end
|
||||
|
||||
if item_id and bit.band(flags, mask) > 0 then
|
||||
if tree:GetItemImage(item_id) == image.DIRECTORY then
|
||||
tree:Toggle(item_id)
|
||||
tree:SelectItem(item_id)
|
||||
else
|
||||
local name = tree:GetItemFullName(item_id)
|
||||
if wx.wxFileExists(name) then LoadFile(name,nil,true) end
|
||||
end
|
||||
else
|
||||
event:Skip()
|
||||
end
|
||||
return true
|
||||
end)
|
||||
local parent
|
||||
tree:Connect(wx.wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT,
|
||||
function (event)
|
||||
local itemsrc = event:GetItem()
|
||||
parent = tree:GetItemParent(itemsrc)
|
||||
if not itemsrc:IsOk() then event:Veto() end
|
||||
end)
|
||||
tree:Connect(wx.wxEVT_COMMAND_TREE_END_LABEL_EDIT,
|
||||
function (event)
|
||||
-- veto the event to keep the original label intact as the tree
|
||||
@@ -389,32 +456,30 @@ local function treeSetConnectorsAndIcons(tree)
|
||||
event:Veto()
|
||||
|
||||
local itemsrc = event:GetItem()
|
||||
if itemsrc == tree:GetRootItem() then return end -- don't edit root
|
||||
if not itemsrc:IsOk() then return end
|
||||
|
||||
local sourcedir = tree:GetItemFullName(tree:GetItemParent(itemsrc))
|
||||
local label = event:GetLabel():gsub("^%s+$","") -- clean all spaces
|
||||
|
||||
-- edited the root element; set the new project directory if needed
|
||||
if tree:IsRoot(itemsrc) then
|
||||
if not event:IsEditCancelled() and wx.wxDirExists(label) then
|
||||
ProjectUpdateProjectDir(label)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if not parent or not parent:IsOk() then return end
|
||||
local sourcedir = tree:GetItemFullName(parent)
|
||||
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()
|
||||
then refreshAncestors(parent) end
|
||||
end)
|
||||
|
||||
local itemsrc
|
||||
tree:Connect(wx.wxEVT_COMMAND_TREE_BEGIN_DRAG,
|
||||
function (event)
|
||||
if event:GetItem() ~= tree:GetRootItem() then
|
||||
if ide.config.filetree.mousemove and tree:GetItemParent(event:GetItem()):IsOk() then
|
||||
itemsrc = event:GetItem()
|
||||
event:Allow()
|
||||
end
|
||||
@@ -422,7 +487,7 @@ local function treeSetConnectorsAndIcons(tree)
|
||||
tree:Connect(wx.wxEVT_COMMAND_TREE_END_DRAG,
|
||||
function (event)
|
||||
local itemdst = event:GetItem()
|
||||
if not itemdst:IsOk() then return end
|
||||
if not itemdst:IsOk() or not itemsrc:IsOk() then return end
|
||||
|
||||
-- check if itemdst is a folder
|
||||
local target = tree:GetItemFullName(itemdst)
|
||||
@@ -436,83 +501,24 @@ local function treeSetConnectorsAndIcons(tree)
|
||||
end
|
||||
|
||||
-- project
|
||||
-- panel
|
||||
-- (combobox, button)
|
||||
-- (treectrl)
|
||||
local projpanel = ide.frame.projpanel
|
||||
local projcombobox = wx.wxComboBox(projpanel, ID "filetree.proj.drivecb",
|
||||
filetree.projdir,
|
||||
wx.wxDefaultPosition, wx.wxDefaultSize,
|
||||
filetree.projdirlist, wx.wxTE_PROCESS_ENTER)
|
||||
|
||||
local projbutton = wx.wxButton(projpanel, ID_PROJECTDIRCHOOSE,
|
||||
"...", wx.wxDefaultPosition, wx.wxSize(26,20))
|
||||
|
||||
local projtree = wx.wxTreeCtrl(projpanel, wx.wxID_ANY,
|
||||
local projtree = wx.wxTreeCtrl(ide.frame, wx.wxID_ANY,
|
||||
wx.wxDefaultPosition, wx.wxDefaultSize,
|
||||
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)
|
||||
projcombobox:SetFont(ide.font.fNormal)
|
||||
filetree.projtree = projtree
|
||||
|
||||
local projTopSizer = wx.wxBoxSizer( wx.wxHORIZONTAL );
|
||||
projTopSizer:Add(projcombobox, 1, wx.wxALL + wx.wxALIGN_LEFT + wx.wxGROW, 0)
|
||||
projTopSizer:Add(projbutton, 0, wx.wxALL + wx.wxALIGN_RIGHT + wx.wxADJUST_MINSIZE + wx.wxALIGN_CENTER_VERTICAL, 0)
|
||||
|
||||
local projSizer = wx.wxBoxSizer( wx.wxVERTICAL );
|
||||
projSizer:Add(projTopSizer, 0, wx.wxALL + wx.wxALIGN_CENTER_HORIZONTAL + wx.wxGROW, 0)
|
||||
projSizer:Add(projtree, 1, wx.wxALL + wx.wxALIGN_LEFT + wx.wxGROW, 0)
|
||||
|
||||
projpanel:SetSizer(projSizer)
|
||||
local projnotebook = ide.frame.projnotebook
|
||||
projnotebook:AddPage(projtree, "Project", true)
|
||||
|
||||
-- proj connectors
|
||||
-- ---------------
|
||||
|
||||
local inupdate = false
|
||||
local function projcomboboxUpdate(event)
|
||||
if inupdate then return end
|
||||
local cur = projcombobox:GetValue()
|
||||
local fn = wx.wxFileName(filetree.projdirmap[cur] or cur)
|
||||
fn:Normalize()
|
||||
|
||||
-- on Windows, wxwidgets (2.9.5+) generates two COMMAND_COMBOBOX_SELECTED
|
||||
-- events when the selection is done with ENTER, which causes recursive
|
||||
-- call of updateProjectDir. To prevent this the second call is ignored.
|
||||
inupdate = true
|
||||
filetree:updateProjectDir(fn:GetFullPath())
|
||||
inupdate = false
|
||||
end
|
||||
|
||||
projpanel:Connect(ID "filetree.proj.drivecb", wx.wxEVT_COMMAND_COMBOBOX_SELECTED, projcomboboxUpdate)
|
||||
projpanel:Connect(ID "filetree.proj.drivecb", wx.wxEVT_COMMAND_TEXT_ENTER, projcomboboxUpdate)
|
||||
|
||||
treeSetConnectorsAndIcons(projtree)
|
||||
|
||||
-- proj functions
|
||||
-- ---------------
|
||||
|
||||
local function abbreviateProjList(projdirlist)
|
||||
filetree.projdirmap = {}
|
||||
local sep = "\t"
|
||||
local dirs = table.concat(projdirlist, sep)..sep
|
||||
local projlist = {}
|
||||
for _, v in ipairs(projdirlist) do
|
||||
-- using FileName because the path doesn't have trailing slash
|
||||
local parts = wx.wxFileName(v..pathsep):GetDirs()
|
||||
local name = table.remove(parts, #parts) or v
|
||||
while #parts > 0
|
||||
and select(2, dirs:gsub("%f[^".. pathsep .."]"..q(name)..sep, "")) > 1 do
|
||||
name = table.remove(parts, #parts) .. pathsep .. name
|
||||
end
|
||||
local abbrev = ("%s (%s)"):format(name, v)
|
||||
filetree.projdirmap[abbrev] = v
|
||||
table.insert(projlist, abbrev)
|
||||
end
|
||||
return projlist
|
||||
end
|
||||
|
||||
function filetree:updateProjectDir(newdir)
|
||||
if (not newdir) or not wx.wxDirExists(newdir) then return end
|
||||
local dirname = wx.wxFileName.DirName(newdir)
|
||||
@@ -524,7 +530,8 @@ function filetree:updateProjectDir(newdir)
|
||||
local newdir = dirname:GetPath(wx.wxPATH_GET_VOLUME)
|
||||
|
||||
if filetree.projdir and #filetree.projdir > 0 then
|
||||
PackageEventHandle("onProjectClose", filetree.projdir) end
|
||||
PackageEventHandle("onProjectClose", filetree.projdir)
|
||||
end
|
||||
|
||||
PackageEventHandle("onProjectPreLoad", newdir)
|
||||
|
||||
@@ -540,32 +547,23 @@ function filetree:updateProjectDir(newdir)
|
||||
newdir,
|
||||
ide.config.projecthistorylength,
|
||||
function(s1, s2) return dirname:SameAs(wx.wxFileName.DirName(s2)) end)
|
||||
projcombobox:Clear()
|
||||
projcombobox:Append(abbreviateProjList(filetree.projdirlist))
|
||||
projcombobox:Select(0)
|
||||
|
||||
ProjectUpdateProjectDir(newdir,true)
|
||||
treeSetRoot(projtree,newdir)
|
||||
|
||||
-- sync with the current editor window and activate selected file
|
||||
local editor = GetEditor()
|
||||
if (editor) then
|
||||
local id = GetEditor():GetId()
|
||||
if ide.openDocuments[id] then
|
||||
FileTreeMarkSelected(ide.openDocuments[id].filePath)
|
||||
end
|
||||
end
|
||||
if editor then FileTreeMarkSelected(ide:GetDocument(editor):GetFilePath()) end
|
||||
|
||||
-- refresh Recent Projects menu item
|
||||
ide.frame:AddPendingEvent(wx.wxUpdateUIEvent(ID_RECENTPROJECTS))
|
||||
|
||||
PackageEventHandle("onProjectLoad", newdir)
|
||||
end
|
||||
|
||||
projpanel.projbutton = projbutton
|
||||
projpanel.projcombobox = projcombobox
|
||||
projpanel.projtree = projtree
|
||||
|
||||
function FileTreeGetDir()
|
||||
return filetree.projdir and #filetree.projdir > 0
|
||||
and wx.wxFileName.DirName(filetree.projdir):GetFullPath()
|
||||
return (filetree.projdir and #filetree.projdir > 0
|
||||
and wx.wxFileName.DirName(filetree.projdir):GetFullPath() or nil)
|
||||
end
|
||||
|
||||
function FileTreeSetProjects(tab)
|
||||
@@ -579,11 +577,60 @@ function FileTreeGetProjects()
|
||||
return filetree.projdirlist
|
||||
end
|
||||
|
||||
local function getProjectLabels()
|
||||
local labels = {}
|
||||
local fmt = ide.config.format.menurecentprojects or '%f'
|
||||
for _, proj in ipairs(FileTreeGetProjects()) do
|
||||
local config = ide.session.projects[proj]
|
||||
local intfname = config and config[2] and config[2].interpreter or ide.interpreter:GetFileName()
|
||||
local interpreter = intfname and ide.interpreters[intfname]
|
||||
local parts = wx.wxFileName(proj..pathsep):GetDirs()
|
||||
table.insert(labels, ExpandPlaceholders(fmt, {
|
||||
f = proj,
|
||||
i = interpreter and interpreter:GetName() or '?',
|
||||
s = parts[#parts] or '',
|
||||
}))
|
||||
end
|
||||
return labels
|
||||
end
|
||||
|
||||
function FileTreeProjectListClear()
|
||||
-- remove all items from the list except the current one
|
||||
filetree.projdirlist = {FileTreeGetDir()}
|
||||
end
|
||||
|
||||
function FileTreeProjectListUpdate(menu, items)
|
||||
-- protect against recent project menu not being present
|
||||
if not ide:FindMenuItem(ID_RECENTPROJECTS) then return end
|
||||
|
||||
local list = getProjectLabels()
|
||||
for i=#list, 1, -1 do
|
||||
local id = ID("file.recentprojects."..i)
|
||||
local label = list[i]
|
||||
if i <= items then -- this is an existing item; update the label
|
||||
menu:FindItem(id):SetItemLabel(label)
|
||||
else -- need to add an item
|
||||
local item = wx.wxMenuItem(menu, id, label, "")
|
||||
menu:Insert(items, item)
|
||||
ide.frame:Connect(id, wx.wxEVT_COMMAND_MENU_SELECTED, function()
|
||||
wx.wxSafeYield() -- let the menu on screen (if any) disappear
|
||||
ProjectUpdateProjectDir(FileTreeGetProjects()[i])
|
||||
end)
|
||||
end
|
||||
-- disable the currently selected project
|
||||
if i == 1 then menu:Enable(id, false) end
|
||||
end
|
||||
for i=items, #list+1, -1 do -- delete the rest if the list got shorter
|
||||
menu:Delete(menu:FindItemByPosition(i-1))
|
||||
end
|
||||
return #list
|
||||
end
|
||||
|
||||
local curr_file
|
||||
function FileTreeMarkSelected(file)
|
||||
if not file or not filetree.projdir or #filetree.projdir == 0 then return end
|
||||
|
||||
local item_id = findItem(projtree, file)
|
||||
local item_id = projtree:FindItem(file)
|
||||
|
||||
-- if the select item is different from the current one
|
||||
-- or the current one is the same, but not bold (which may happen when
|
||||
@@ -591,7 +638,7 @@ function FileTreeMarkSelected(file)
|
||||
if curr_file ~= file
|
||||
or item_id and not projtree:IsBold(item_id) then
|
||||
if curr_file then
|
||||
local curr_id = findItem(projtree, curr_file)
|
||||
local curr_id = projtree:FindItem(curr_file)
|
||||
if curr_id and projtree:IsBold(curr_id) then
|
||||
projtree:SetItemBold(curr_id, false)
|
||||
end
|
||||
@@ -603,7 +650,8 @@ function FileTreeMarkSelected(file)
|
||||
end
|
||||
curr_file = file
|
||||
if ide.wxver < "2.9.5" and ide.osname == 'Macintosh' then
|
||||
projtree:Refresh() end
|
||||
projtree:Refresh()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
-- Copyright 2011-14 Paul Kulchenko, ZeroBrane LLC
|
||||
-- authors: Lomtik Software (J. Winwood & John Labenski)
|
||||
-- Luxinia Dev (Eike Decker & Christoph Kubisch)
|
||||
---------------------------------------------------------
|
||||
|
||||
local ide = ide
|
||||
ide.findReplace = {
|
||||
dialog = nil, -- the wxDialog for find/replace
|
||||
@@ -16,6 +18,8 @@ ide.findReplace = {
|
||||
fSubDirs = true, -- search in subdirectories
|
||||
fMakeBak = true, -- make bak files for replace in files
|
||||
|
||||
buttons = {},
|
||||
|
||||
findTextArray = {}, -- array of last entered find text
|
||||
findText = "", -- string to find
|
||||
replaceTextArray = {}, -- array of last entered replace text
|
||||
@@ -39,8 +43,12 @@ ide.findReplace = {
|
||||
}
|
||||
local findReplace = ide.findReplace
|
||||
|
||||
local lastEditor
|
||||
function findReplace:GetEditor()
|
||||
return findReplace.oveditor or GetEditor()
|
||||
lastEditor = findReplace.oveditor or GetEditorWithFocus() or lastEditor
|
||||
-- last editor may already be "userdata" instead of a Scintilla object,
|
||||
-- so check if this is still a valid wxSTC object
|
||||
return pcall(function() lastEditor:GetId() end) and lastEditor or GetEditor()
|
||||
end
|
||||
|
||||
-------------------- Find replace dialog
|
||||
@@ -95,7 +103,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
|
||||
@@ -141,7 +149,7 @@ function findReplace:FindString(reverse)
|
||||
findReplace.foundString = true
|
||||
local start = editor:GetTargetStart()
|
||||
local finish = editor:GetTargetEnd()
|
||||
EnsureRangeVisible(start, finish)
|
||||
editor:EnsureVisibleEnforcePolicy(editor:LineFromPosition(start))
|
||||
editor:SetSelection(start, finish)
|
||||
ide.frame:SetStatusText("")
|
||||
end
|
||||
@@ -186,6 +194,9 @@ function findReplace:ReplaceString(fReplaceAll, inFileRegister)
|
||||
|
||||
if findReplace:HasText() then
|
||||
local editor = findReplace:GetEditor()
|
||||
-- don't replace in read-only editors
|
||||
if editor:GetReadOnly() then return false end
|
||||
|
||||
local endTarget = inFileRegister and setTargetAll(editor) or
|
||||
setTarget(editor, findReplace.fDown, fReplaceAll, findReplace.fWrap)
|
||||
|
||||
@@ -280,7 +291,7 @@ local function ProcInFiles(startdir,mask,subdirs,replace)
|
||||
if replace then
|
||||
-- check if anything replaced, store changed content, make .bak
|
||||
if findReplace:ReplaceString(true,onFileRegister)
|
||||
and findReplace.fMakeBak and FileWrite(file..".bak",filetext) then
|
||||
and (not findReplace.fMakeBak or FileWrite(file..".bak",filetext)) then
|
||||
FileWrite(file,findReplace.oveditor:GetText())
|
||||
end
|
||||
else
|
||||
@@ -288,7 +299,7 @@ local function ProcInFiles(startdir,mask,subdirs,replace)
|
||||
end
|
||||
|
||||
-- give time to the UI to refresh
|
||||
if TimeGet() - start > 0.25 then wx.wxYield() end
|
||||
if TimeGet() - start > 0.25 then ide:Yield() end
|
||||
if not findReplace.dialog:IsShown() then
|
||||
DisplayOutputLn(TR("Cancelled by the user."))
|
||||
break
|
||||
@@ -303,7 +314,7 @@ function findReplace:RunInFiles(replace)
|
||||
if not findReplace:HasText() then return end
|
||||
|
||||
findReplace.oveditor = wxstc.wxStyledTextCtrl(findReplace.dialog, wx.wxID_ANY,
|
||||
wx.wxDefaultPosition, wx.wxSize(1,1), wx.wxBORDER_STATIC)
|
||||
wx.wxDefaultPosition, wx.wxSize(1,1), wx.wxBORDER_NONE)
|
||||
findReplace.occurrences = 0
|
||||
|
||||
ActivateOutput()
|
||||
@@ -544,6 +555,7 @@ function findReplace:createDialog(replace,infiles)
|
||||
function()
|
||||
TransferDataFromWindow()
|
||||
if (findReplace.infiles) then
|
||||
for _, b in pairs(findReplace.buttons) do b:Disable() end
|
||||
findReplace:RunInFiles()
|
||||
findReplace.dialog:Destroy()
|
||||
findReplace.dialog = nil
|
||||
@@ -558,6 +570,7 @@ function findReplace:createDialog(replace,infiles)
|
||||
event:Skip()
|
||||
if findReplace.replace then
|
||||
if (findReplace.infiles) then
|
||||
for _, b in pairs(findReplace.buttons) do b:Disable() end
|
||||
findReplace:RunInFiles(true)
|
||||
findReplace.dialog:Destroy()
|
||||
findReplace.dialog = nil
|
||||
@@ -588,23 +601,32 @@ function findReplace:createDialog(replace,infiles)
|
||||
if res == wx.wxID_OK then
|
||||
infilesDirCombo:SetValue(FixDir(filePicker:GetPath()))
|
||||
end
|
||||
-- when the dropdown is used to select the directory on OSX,
|
||||
-- the find dialog moves to the background; this keeps it on top.
|
||||
if ide.osname == 'Macintosh' then findDialog:Raise() end
|
||||
end)
|
||||
end
|
||||
|
||||
-- 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())
|
||||
else
|
||||
findButton:SetDefault()
|
||||
end
|
||||
|
||||
-- reset search when re-creating dialog to avoid modifying selected
|
||||
-- fragment after successful search and updated replacement
|
||||
findReplace.foundString = false
|
||||
findReplace.dialog = findDialog
|
||||
findDialog:Show(true)
|
||||
|
||||
-- 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).
|
||||
-- SetFocus has to be done after :Show on OSX as it doesn't put
|
||||
-- the focus on the Find field on some instances of OSX 10.9.2.
|
||||
if mac then
|
||||
findTextCombo:SetSelection(-1, -1)
|
||||
findTextCombo:SetFocus() -- force focus on the Find
|
||||
else
|
||||
findButton:SetDefault()
|
||||
end
|
||||
|
||||
findReplace.buttons = {findButton, replaceButton}
|
||||
|
||||
return findDialog
|
||||
end
|
||||
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
-- Copyright 2011-14 Paul Kulchenko, ZeroBrane LLC
|
||||
-- authors: Luxinia Dev (Eike Decker & Christoph Kubisch)
|
||||
-- Lomtik Software (J. Winwood & John Labenski)
|
||||
---------------------------------------------------------
|
||||
|
||||
local ide = ide
|
||||
local unpack = table.unpack or unpack
|
||||
|
||||
-- Pick some reasonable fixed width fonts to use for the editor
|
||||
local function setFont(style, config)
|
||||
@@ -51,11 +54,11 @@ local function createFrame()
|
||||
local statusBar = frame:CreateStatusBar(6)
|
||||
local section_width = statusBar:GetTextExtent("OVRW")
|
||||
statusBar:SetStatusStyles({wx.wxSB_FLAT, wx.wxSB_FLAT, wx.wxSB_FLAT,
|
||||
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()
|
||||
mgr:SetManagedWindow(frame)
|
||||
|
||||
@@ -71,41 +74,76 @@ local function SCinB(id) -- shortcut in brackets
|
||||
return shortcut and #shortcut > 0 and (" ("..shortcut..")") or ""
|
||||
end
|
||||
|
||||
local function menuDropDownPosition(event)
|
||||
local tb = event:GetEventObject():DynamicCast('wxAuiToolBar')
|
||||
local rect = tb:GetToolRect(event:GetId())
|
||||
return ide.frame:ScreenToClient(tb:ClientToScreen(rect:GetBottomLeft()))
|
||||
end
|
||||
|
||||
local function tbIconSize()
|
||||
local iconsize = (tonumber(ide.config.toolbar and ide.config.toolbar.iconsize)
|
||||
or (ide.osname == 'Macintosh' and 24 or 16))
|
||||
if iconsize ~= 24 then iconsize = 16 end
|
||||
return iconsize
|
||||
end
|
||||
|
||||
local function createToolBar(frame)
|
||||
local toolBar = frame:CreateToolBar(wx.wxTB_FLAT + wx.wxTB_NODIVIDER, wx.wxID_ANY)
|
||||
local toolBar = wxaui.wxAuiToolBar(frame, wx.wxID_ANY, wx.wxDefaultPosition, wx.wxDefaultSize,
|
||||
wxaui.wxAUI_TB_PLAIN_BACKGROUND)
|
||||
-- wxChoice is a bit too narrow on Linux, so make it a bit larger
|
||||
local funclist = wx.wxChoice.new(toolBar, ID "toolBar.funclist",
|
||||
wx.wxDefaultPosition, wx.wxSize.new(240, ide.osname == 'Unix' and 28 or 24))
|
||||
|
||||
|
||||
-- there are two sets of icons: use 24 on OSX and 16 on others.
|
||||
local toolBmpSize =
|
||||
ide.osname == 'Macintosh' and wx.wxSize(24, 24) or wx.wxSize(16, 16)
|
||||
local iconsize = tbIconSize()
|
||||
local toolBmpSize = wx.wxSize(iconsize, iconsize)
|
||||
local getBitmap = (ide.app.createbitmap or wx.wxArtProvider.GetBitmap)
|
||||
toolBar:AddTool(ID_NEW, "New", getBitmap(wx.wxART_NORMAL_FILE, wx.wxART_TOOLBAR, toolBmpSize), TR("Create an empty document")..SCinB(ID_NEW))
|
||||
toolBar:AddTool(ID_OPEN, "Open", getBitmap(wx.wxART_FILE_OPEN, wx.wxART_TOOLBAR, toolBmpSize), TR("Open an existing document")..SCinB(ID_OPEN))
|
||||
toolBar:AddTool(ID_SAVE, "Save", getBitmap(wx.wxART_FILE_SAVE, wx.wxART_TOOLBAR, toolBmpSize), TR("Save the current document")..SCinB(ID_SAVE))
|
||||
toolBar:AddTool(ID_SAVEALL, "Save All", getBitmap(wx.wxART_NEW_DIR, wx.wxART_TOOLBAR, toolBmpSize), TR("Save all open documents")..SCinB(ID_SAVEALL))
|
||||
toolBar:AddTool(ID_PROJECTDIRFROMFILE, "Update", getBitmap(wx.wxART_GO_DIR_UP , wx.wxART_TOOLBAR, toolBmpSize), TR("Set project directory from current file")..SCinB(ID_PROJECTDIRFROMFILE))
|
||||
toolBar:AddSeparator()
|
||||
toolBar:AddTool(ID_FIND, "Find", getBitmap(wx.wxART_FIND, wx.wxART_TOOLBAR, toolBmpSize), TR("Find text")..SCinB(ID_FIND))
|
||||
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 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))
|
||||
toolBar:AddTool(ID_STEPOVER, "Step over", getBitmap("wxART_DEBUG_STEP_OVER", wx.wxART_TOOLBAR, toolBmpSize), TR("Step over")..SCinB(ID_STEPOVER))
|
||||
toolBar:AddTool(ID_STEPOUT, "Step out", getBitmap("wxART_DEBUG_STEP_OUT", wx.wxART_TOOLBAR, toolBmpSize), TR("Step out of the current function")..SCinB(ID_STEPOUT))
|
||||
toolBar:AddSeparator()
|
||||
toolBar:AddTool(ID_TOGGLEBREAKPOINT, "Toggle breakpoint", getBitmap("wxART_DEBUG_BREAKPOINT_TOGGLE", wx.wxART_TOOLBAR, toolBmpSize), TR("Toggle breakpoint")..SCinB(ID_TOGGLEBREAKPOINT))
|
||||
toolBar:AddTool(ID_VIEWCALLSTACK, "Stack window", getBitmap("wxART_DEBUG_CALLSTACK", wx.wxART_TOOLBAR, toolBmpSize), TR("View the stack window")..SCinB(ID_VIEWCALLSTACK))
|
||||
toolBar:AddTool(ID_VIEWWATCHWINDOW, "Watch window", getBitmap("wxART_DEBUG_WATCH", wx.wxART_TOOLBAR, toolBmpSize), TR("View the watch window")..SCinB(ID_VIEWWATCHWINDOW))
|
||||
local icons, prev = ide.config.toolbar.icons
|
||||
for _, id in ipairs(icons) do
|
||||
if icons[id] ~= false then -- skip explicitly disabled icons
|
||||
if id == ID_SEPARATOR then
|
||||
-- make sure that there are no two separators next to each other;
|
||||
-- this may happen when some of the icons are disabled.
|
||||
if prev ~= ID_SEPARATOR then toolBar:AddSeparator() end
|
||||
else
|
||||
local iconmap = ide.config.toolbar.iconmap[id]
|
||||
if iconmap then
|
||||
local icon, description = unpack(iconmap)
|
||||
local isbitmap = type(icon) == "userdata" and icon:GetClassInfo():GetClassName() == "wxBitmap"
|
||||
local bitmap = isbitmap and icon or getBitmap(icon, "TOOLBAR", toolBmpSize)
|
||||
toolBar:AddTool(id, "", bitmap, TR(description)..SCinB(id))
|
||||
end
|
||||
end
|
||||
prev = id
|
||||
end
|
||||
end
|
||||
toolBar:AddSeparator()
|
||||
toolBar:AddControl(funclist)
|
||||
|
||||
toolBar:SetToolDropDown(ID_OPEN, true)
|
||||
toolBar:Connect(ID_OPEN, wxaui.wxEVT_COMMAND_AUITOOLBAR_TOOL_DROPDOWN, function(event)
|
||||
if event:IsDropDownClicked() then
|
||||
local menu = wx.wxMenu()
|
||||
FileRecentListUpdate(menu)
|
||||
toolBar:PopupMenu(menu, menuDropDownPosition(event))
|
||||
else
|
||||
event:Skip()
|
||||
end
|
||||
end)
|
||||
|
||||
toolBar:SetToolDropDown(ID_PROJECTDIRCHOOSE, true)
|
||||
toolBar:Connect(ID_PROJECTDIRCHOOSE, wxaui.wxEVT_COMMAND_AUITOOLBAR_TOOL_DROPDOWN, function(event)
|
||||
if event:IsDropDownClicked() then
|
||||
local menu = wx.wxMenu()
|
||||
FileTreeProjectListUpdate(menu, 0)
|
||||
toolBar:PopupMenu(menu, menuDropDownPosition(event))
|
||||
else
|
||||
event:Skip()
|
||||
end
|
||||
end)
|
||||
|
||||
toolBar:GetArtProvider():SetElementSize(wxaui.wxAUI_TBART_GRIPPER_SIZE, 0)
|
||||
toolBar:Realize()
|
||||
|
||||
|
||||
toolBar.funclist = funclist
|
||||
frame.toolBar = toolBar
|
||||
return toolBar
|
||||
@@ -114,9 +152,9 @@ end
|
||||
local function createNotebook(frame)
|
||||
-- notebook for editors
|
||||
local notebook = wxaui.wxAuiNotebook(frame, wx.wxID_ANY,
|
||||
wx.wxDefaultPosition, wx.wxDefaultSize,
|
||||
wxaui.wxAUI_NB_DEFAULT_STYLE + wxaui.wxAUI_NB_TAB_EXTERNAL_MOVE
|
||||
+ wxaui.wxAUI_NB_WINDOWLIST_BUTTON + wx.wxNO_BORDER)
|
||||
wx.wxDefaultPosition, wx.wxDefaultSize,
|
||||
wxaui.wxAUI_NB_DEFAULT_STYLE + wxaui.wxAUI_NB_TAB_EXTERNAL_MOVE
|
||||
+ wxaui.wxAUI_NB_WINDOWLIST_BUTTON + wx.wxNO_BORDER)
|
||||
|
||||
-- wxEVT_SET_FOCUS could be used, but it only works on Windows with wx2.9.5+
|
||||
notebook:Connect(wxaui.wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED,
|
||||
@@ -137,7 +175,8 @@ local function createNotebook(frame)
|
||||
and debug:traceback():find("'AddPage'"))
|
||||
|
||||
if doc and event:GetOldSelection() ~= -1 and not double then
|
||||
SetEditorSelection(notebook:GetSelection()) end
|
||||
SetEditorSelection(notebook:GetSelection())
|
||||
end
|
||||
end)
|
||||
|
||||
notebook:Connect(wxaui.wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE,
|
||||
@@ -146,6 +185,24 @@ local function createNotebook(frame)
|
||||
event:Veto() -- don't propagate the event as the page is already closed
|
||||
end)
|
||||
|
||||
notebook:Connect(wxaui.wxEVT_COMMAND_AUINOTEBOOK_BG_DCLICK,
|
||||
function (event)
|
||||
-- as this event can be on different tab controls,
|
||||
-- need to find the control to add the page to
|
||||
local tabctrl = event:GetEventObject():DynamicCast("wxAuiTabCtrl")
|
||||
-- check if the active page is in the current control
|
||||
local active = tabctrl:GetActivePage()
|
||||
if (active >= 0 and tabctrl:GetPage(active).window
|
||||
~= notebook:GetPage(notebook:GetSelection())) then
|
||||
-- if not, need to activate the control that was clicked on;
|
||||
-- find the last window and switch to it (assuming there is always one)
|
||||
assert(tabctrl:GetPageCount() >= 1, "Expected at least one page in a notebook tab control.")
|
||||
local lastwin = tabctrl:GetPage(tabctrl:GetPageCount()-1).window
|
||||
notebook:SetSelection(notebook:GetPageIndex(lastwin))
|
||||
end
|
||||
NewFile()
|
||||
end)
|
||||
|
||||
-- tabs can be dragged around which may change their indexes;
|
||||
-- when this happens stored indexes need to be updated to reflect the change.
|
||||
-- there is DRAG_DONE event that I'd prefer to use, but it
|
||||
@@ -157,6 +214,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
|
||||
@@ -181,6 +240,7 @@ local function createNotebook(frame)
|
||||
{ ID_SAVE, TR("&Save") },
|
||||
{ ID_SAVEAS, TR("Save &As...") },
|
||||
{ },
|
||||
{ ID_COPYFULLPATH, TR("Copy Full Path") },
|
||||
{ ID_SHOWLOCATION, TR("Show Location") },
|
||||
}
|
||||
|
||||
@@ -192,7 +252,7 @@ local function createNotebook(frame)
|
||||
local function IfAtLeastOneTab(event)
|
||||
event:Enable(notebook:GetPageCount() > 0)
|
||||
if ide.osname == 'Macintosh' and (event:GetId() == ID_CLOSEALL
|
||||
or event:GetId() == ID_CLOSE and notebook:GetPageCount() <= 1)
|
||||
or event:GetId() == ID_CLOSE and notebook:GetPageCount() <= 1)
|
||||
then event:Enable(false) end
|
||||
end
|
||||
local function IfModified(event) event:Enable(EditorIsModified(GetEditor(selection))) end
|
||||
@@ -225,6 +285,14 @@ local function createNotebook(frame)
|
||||
end)
|
||||
notebook:Connect(ID_SHOWLOCATION, wx.wxEVT_UPDATE_UI, IfAtLeastOneTab)
|
||||
|
||||
notebook:Connect(ID_COPYFULLPATH, wx.wxEVT_COMMAND_MENU_SELECTED, function()
|
||||
local tdo = wx.wxTextDataObject(ide:GetDocument(GetEditor(selection)):GetFilePath())
|
||||
if wx.wxClipboard:Get():Open() then
|
||||
wx.wxClipboard:Get():SetData(tdo)
|
||||
wx.wxClipboard:Get():Close()
|
||||
end
|
||||
end)
|
||||
|
||||
frame.notebook = notebook
|
||||
return notebook
|
||||
end
|
||||
@@ -257,7 +325,7 @@ local function createBottomNotebook(frame)
|
||||
local mouse = wx.wxGetMouseState()
|
||||
local mouseatpoint = wx.wxPoint(mouse:GetX(), mouse:GetY())
|
||||
local ok, tabs = pcall(function() return wx.wxFindWindowAtPoint(mouseatpoint):DynamicCast("wxAuiTabCtrl") end)
|
||||
tabs:SetNoneActive()
|
||||
if ok then tabs:SetNoneActive() end
|
||||
|
||||
event:Allow()
|
||||
end
|
||||
@@ -319,8 +387,10 @@ local function createBottomNotebook(frame)
|
||||
local label = bottomnotebook:GetPageText(selection)
|
||||
|
||||
-- names are translated on labels, so need to translate here as well
|
||||
local dragout = ({[TR("Watch")] = DebuggerAddWatchWindow,
|
||||
[TR("Stack")] = DebuggerAddStackWindow})[label]
|
||||
local dragout = ({
|
||||
[TR("Watch")] = DebuggerAddWatchWindow,
|
||||
[TR("Stack")] = DebuggerAddStackWindow,
|
||||
})[label]
|
||||
if not dragout then return end
|
||||
|
||||
bottomnotebook:RemovePage(selection)
|
||||
@@ -331,26 +401,60 @@ local function createBottomNotebook(frame)
|
||||
mgr:Update()
|
||||
end)
|
||||
|
||||
-- disallow tabs closing
|
||||
bottomnotebook:Connect(wxaui.wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE,
|
||||
function (event) event:Veto() end)
|
||||
|
||||
local errorlog = wxstc.wxStyledTextCtrl(bottomnotebook, wx.wxID_ANY,
|
||||
wx.wxDefaultPosition, wx.wxDefaultSize, wx.wxBORDER_STATIC)
|
||||
wx.wxDefaultPosition, wx.wxDefaultSize, wx.wxBORDER_NONE)
|
||||
|
||||
errorlog:Connect(wx.wxEVT_CONTEXT_MENU,
|
||||
function (event)
|
||||
errorlog:PopupMenu(
|
||||
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_CLEAROUTPUT, TR("C&lear Output Window") },
|
||||
}
|
||||
)
|
||||
end)
|
||||
|
||||
errorlog:Connect(ID_CLEAROUTPUT, wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
function(event)
|
||||
ClearOutput()
|
||||
end)
|
||||
|
||||
local shellbox = wxstc.wxStyledTextCtrl(bottomnotebook, wx.wxID_ANY,
|
||||
wx.wxDefaultPosition, wx.wxDefaultSize, wx.wxBORDER_STATIC)
|
||||
wx.wxDefaultPosition, wx.wxDefaultSize, wx.wxBORDER_NONE)
|
||||
|
||||
bottomnotebook:AddPage(errorlog, TR("Output"), true)
|
||||
bottomnotebook:AddPage(shellbox, TR("Local console"), false)
|
||||
|
||||
frame.bottomnotebook = bottomnotebook
|
||||
|
||||
bottomnotebook.errorlog = errorlog
|
||||
bottomnotebook.shellbox = shellbox
|
||||
|
||||
|
||||
frame.bottomnotebook = bottomnotebook
|
||||
return bottomnotebook
|
||||
end
|
||||
|
||||
local function createProjpanel(frame)
|
||||
local projpanel = wx.wxPanel(frame,wx.wxID_ANY)
|
||||
frame.projpanel = projpanel
|
||||
return projpanel
|
||||
local function createProjNotebook(frame)
|
||||
local projnotebook = wxaui.wxAuiNotebook(frame, wx.wxID_ANY,
|
||||
wx.wxDefaultPosition, wx.wxDefaultSize,
|
||||
wxaui.wxAUI_NB_DEFAULT_STYLE
|
||||
- wxaui.wxAUI_NB_CLOSE_ON_ACTIVE_TAB + wx.wxNO_BORDER)
|
||||
|
||||
-- disallow tabs closing
|
||||
projnotebook:Connect(wxaui.wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE,
|
||||
function (event) event:Veto() end)
|
||||
|
||||
frame.projnotebook = projnotebook
|
||||
return projnotebook
|
||||
end
|
||||
|
||||
-- ----------------------------------------------------------------------------
|
||||
@@ -360,26 +464,40 @@ local frame = createFrame()
|
||||
ide.frame = frame
|
||||
createToolBar(frame)
|
||||
createNotebook(frame)
|
||||
createProjpanel(frame)
|
||||
createProjNotebook(frame)
|
||||
createBottomNotebook(frame)
|
||||
|
||||
do
|
||||
local frame = ide.frame
|
||||
local mgr = frame.uimgr
|
||||
|
||||
mgr:AddPane(frame.toolBar, wxaui.wxAuiPaneInfo():
|
||||
Name("toolbar"):Caption("Toolbar"):
|
||||
ToolbarPane():Top():CloseButton(false):PaneBorder(false):
|
||||
LeftDockable(false):RightDockable(false))
|
||||
mgr:AddPane(frame.notebook, wxaui.wxAuiPaneInfo():
|
||||
Name("notebook"):
|
||||
CenterPane():PaneBorder(false))
|
||||
mgr:AddPane(frame.projpanel, wxaui.wxAuiPaneInfo():
|
||||
Name("projpanel"):Caption(TR("Project")):
|
||||
MinSize(200,200):FloatingSize(200,400):
|
||||
Left():Layer(1):Position(1):
|
||||
CloseButton(true):MaximizeButton(false):PinButton(true))
|
||||
Name("notebook"):
|
||||
CenterPane():PaneBorder(false))
|
||||
mgr:AddPane(frame.projnotebook, wxaui.wxAuiPaneInfo():
|
||||
Name("projpanel"):CaptionVisible(false):Caption(TR("Project")):
|
||||
MinSize(200,200):FloatingSize(200,400):
|
||||
Left():Layer(1):Position(1):PaneBorder(false):
|
||||
CloseButton(true):MaximizeButton(false):PinButton(true))
|
||||
mgr:AddPane(frame.bottomnotebook, wxaui.wxAuiPaneInfo():
|
||||
Name("bottomnotebook"):
|
||||
MinSize(100,100):BestSize(200,200):FloatingSize(400,200):
|
||||
Bottom():Layer(1):Position(1):
|
||||
CloseButton(true):MaximizeButton(false):PinButton(true))
|
||||
Name("bottomnotebook"):CaptionVisible(false):
|
||||
MinSize(100,100):BestSize(200,200):FloatingSize(400,200):
|
||||
Bottom():Layer(1):Position(1):PaneBorder(false):
|
||||
CloseButton(true):MaximizeButton(false):PinButton(true))
|
||||
|
||||
for _, uimgr in pairs {mgr, frame.notebook:GetAuiManager(),
|
||||
frame.bottomnotebook:GetAuiManager(), frame.projnotebook:GetAuiManager()} do
|
||||
uimgr:GetArtProvider():SetMetric(wxaui.wxAUI_DOCKART_SASH_SIZE, 2)
|
||||
end
|
||||
|
||||
for _, nb in pairs {frame.bottomnotebook, frame.projnotebook} do
|
||||
nb:Connect(wxaui.wxEVT_COMMAND_AUINOTEBOOK_BG_DCLICK,
|
||||
function() PaneFloatToggle(nb) end)
|
||||
end
|
||||
|
||||
mgr.defaultPerspective = mgr:SavePerspective()
|
||||
end
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
-- Copyright 2011-14 Paul Kulchenko, ZeroBrane LLC
|
||||
-- authors: Lomtik Software (J. Winwood & John Labenski)
|
||||
-- Luxinia Dev (Eike Decker & Christoph Kubisch)
|
||||
---------------------------------------------------------
|
||||
@@ -9,9 +10,14 @@ 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'
|
||||
|
||||
ID_SEPARATOR = NewID()
|
||||
-- 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()
|
||||
@@ -22,35 +28,47 @@ 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_RECENTFILESCLEAR = NewID()
|
||||
ID_RECENTFILESPREV = NewID()
|
||||
ID_RECENTFILESNEXT = NewID()
|
||||
ID_EXIT = wx.wxID_EXIT
|
||||
ID_RECENTPROJECTS = NewID()
|
||||
ID_RECENTPROJECTSCLEAR = NewID()
|
||||
ID_RECENTPROJECTSPREV = NewID()
|
||||
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()
|
||||
ID_COMMENT = NewID()
|
||||
ID_FOLD = NewID()
|
||||
ID_CLEARDYNAMICWORDS = NewID()
|
||||
ID_SOURCE = NewID()
|
||||
ID_REINDENT = NewID()
|
||||
ID_BOOKMARK = NewID()
|
||||
ID_BOOKMARKTOGGLE = NewID()
|
||||
ID_BOOKMARKNEXT = NewID()
|
||||
ID_BOOKMARKPREV = NewID()
|
||||
-- don't use wx.wxID_PREFERENCES to avoid merging with OSX app menu, because
|
||||
-- Apple guidelines describe Preferences as a "normal" item without submenus.
|
||||
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()
|
||||
@@ -61,8 +79,15 @@ ID_VIEWFILETREE = NewID()
|
||||
ID_VIEWOUTPUT = NewID()
|
||||
ID_VIEWCALLSTACK = NewID()
|
||||
ID_VIEWWATCHWINDOW = NewID()
|
||||
ID_VIEWTOOLBAR = NewID()
|
||||
ID_VIEWSTATUSBAR = NewID()
|
||||
ID_VIEWDEFAULTLAYOUT = NewID()
|
||||
ID_VIEWFULLSCREEN = NewID()
|
||||
ID_VIEWMINIMIZE = NewID()
|
||||
ID_ZOOM = NewID()
|
||||
ID_ZOOMRESET = NewID()
|
||||
ID_ZOOMIN = NewID()
|
||||
ID_ZOOMOUT = NewID()
|
||||
-- Project menu
|
||||
ID_TOGGLEBREAKPOINT = NewID()
|
||||
ID_COMPILE = NewID()
|
||||
@@ -72,18 +97,20 @@ ID_RUNNOW = NewID()
|
||||
ID_ATTACHDEBUG = NewID()
|
||||
ID_STARTDEBUG = NewID()
|
||||
ID_STOPDEBUG = NewID()
|
||||
ID_DETACHDEBUG = NewID()
|
||||
ID_STEP = NewID()
|
||||
ID_STEPOVER = NewID()
|
||||
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()
|
||||
@@ -97,6 +124,7 @@ ID_DELETEWATCH = NewID()
|
||||
-- Editor popup menu items
|
||||
ID_GOTODEFINITION = NewID()
|
||||
ID_RENAMEALLINSTANCES = NewID()
|
||||
ID_REPLACEALLSELECTIONS = NewID()
|
||||
ID_QUICKADDWATCH = NewID()
|
||||
ID_QUICKEVAL = NewID()
|
||||
ID_ADDTOSCRATCHPAD = NewID()
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
-- Copyright 2012-14 Paul Kulchenko, ZeroBrane LLC
|
||||
-- Integration with LuaInspect
|
||||
-- (C) 2012 Paul Kulchenko
|
||||
---------------------------------------------------------
|
||||
|
||||
local M, LA, LI, T = {}
|
||||
local FAST = true
|
||||
@@ -7,7 +8,11 @@ local FAST = true
|
||||
local function init()
|
||||
if LA then return end
|
||||
|
||||
require "metalua"
|
||||
-- metalua is using 'checks', which noticeably slows the execution
|
||||
-- stab it with out own
|
||||
package.loaded.checks = {}
|
||||
checks = function() end
|
||||
|
||||
LA = require "luainspect.ast"
|
||||
LI = require "luainspect.init"
|
||||
T = require "luainspect.types"
|
||||
@@ -33,26 +38,45 @@ function M.warnings_from_string(src, file)
|
||||
LI.mark_related_keywords(ast, tokenlist, src)
|
||||
end
|
||||
|
||||
return M.show_warnings(ast)
|
||||
local globinit = {}
|
||||
local spec = GetSpec(wx.wxFileName(file):GetExt())
|
||||
for k in pairs(spec and GetApi(spec.apitype or "none").ac.childs or {}) do
|
||||
globinit[k] = true
|
||||
end
|
||||
|
||||
return M.show_warnings(ast, globinit)
|
||||
end
|
||||
|
||||
function M.show_warnings(top_ast)
|
||||
local function cleanError(err)
|
||||
return err and err:gsub(".-:%d+: file%s+",""):gsub(", line (%d+), char %d+", ":%1")
|
||||
end
|
||||
|
||||
function AnalyzeFile(file)
|
||||
local warn, err, line, pos = M.warnings_from_string(FileRead(file), file)
|
||||
return warn, cleanError(err), line, pos
|
||||
end
|
||||
|
||||
function AnalyzeString(src)
|
||||
local warn, err, line, pos = M.warnings_from_string(src, "<string>")
|
||||
return warn, cleanError(err), line, pos
|
||||
end
|
||||
|
||||
function M.show_warnings(top_ast, globinit)
|
||||
local warnings = {}
|
||||
local function warn(msg, linenum, path)
|
||||
warnings[#warnings+1] = (path or "?") .. "(" .. (linenum or 0) .. "): " .. msg
|
||||
warnings[#warnings+1] = (path or "?") .. ":" .. (linenum or 0) .. ": " .. msg
|
||||
end
|
||||
local function known(o) return not T.istype[o] end
|
||||
local function index(f) -- build abc.def.xyz name recursively
|
||||
return (f[1].tag == 'Id' and f[1][1] or index(f[1])) .. '.' .. f[2][1] end
|
||||
local isseen, globseen, fieldseen = {}, {}, {}
|
||||
local globseen, isseen, fieldseen = globinit or {}, {}, {}
|
||||
LA.walk(top_ast, function(ast)
|
||||
local line = ast.lineinfo and ast.lineinfo.first[1] or 0
|
||||
local path = ast.lineinfo and ast.lineinfo.first[4] or '?'
|
||||
local path, line = tostring(ast.lineinfo):gsub('<C|','<'):match('<([^|]+)|L(%d+)')
|
||||
local name = ast[1]
|
||||
-- check if we're masking a variable in the same scope
|
||||
if ast.localmasking and name ~= '_' and
|
||||
ast.level == ast.localmasking.level then
|
||||
local linenum = ast.localmasking.lineinfo.first[1]
|
||||
local linenum = tostring(ast.localmasking.lineinfo.first):match('|L(%d+)')
|
||||
local parent = ast.parent and ast.parent.parent
|
||||
local func = parent and parent.tag == 'Localrec'
|
||||
warn("local " .. (func and 'function' or 'variable') .. " '" ..
|
||||
@@ -111,7 +135,7 @@ function M.show_warnings(top_ast)
|
||||
and (" in '"..index(ast.parent):gsub("%."..name.."$","").."'")
|
||||
or ""
|
||||
warn("first use of unknown field '" .. name .."'"..parent,
|
||||
ast.lineinfo.first[1], path)
|
||||
tostring(ast.lineinfo.first):match('|L(%d+)'), path)
|
||||
end
|
||||
elseif ast.tag == 'Id' and not ast.localdefinition and not ast.definedglobal then
|
||||
if not globseen[name] then
|
||||
@@ -152,31 +176,27 @@ function M.show_warnings(top_ast)
|
||||
end
|
||||
|
||||
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 _, menu, compilepos = ide:FindMenuItem(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
|
||||
local openDocuments = ide.openDocuments
|
||||
|
||||
local function analyzeProgram(editor)
|
||||
local editorText = editor:GetText()
|
||||
local id = editor:GetId()
|
||||
local filePath = DebuggerMakeFileName(editor, openDocuments[id].filePath)
|
||||
|
||||
if frame.menuBar:IsChecked(ID_CLEAROUTPUT) then ClearOutput() end
|
||||
if ide:GetMenuBar():IsChecked(ID_CLEAROUTPUT) then ClearOutput() end
|
||||
DisplayOutput("Analyzing the source code")
|
||||
frame:Update()
|
||||
|
||||
local editorText = editor:GetText()
|
||||
local doc = ide:GetDocument(editor)
|
||||
local filePath = doc:GetFilePath() or doc:GetFileName()
|
||||
local warn, err = M.warnings_from_string(editorText, filePath)
|
||||
if err then -- report compilation error
|
||||
DisplayOutput(": not completed\n")
|
||||
DisplayOutput((": not completed.\n%s\n"):format(cleanError(err)))
|
||||
return false
|
||||
end
|
||||
|
||||
@@ -191,7 +211,9 @@ frame:Connect(ID_ANALYZE, wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
function ()
|
||||
ActivateOutput()
|
||||
local editor = GetEditor()
|
||||
if not analyzeProgram(editor) then CompileProgram(editor, { reportstats = false }) end
|
||||
if not analyzeProgram(editor) then
|
||||
CompileProgram(editor, { reportstats = false, keepoutput = true })
|
||||
end
|
||||
end)
|
||||
frame:Connect(ID_ANALYZE, wx.wxEVT_UPDATE_UI,
|
||||
function (event)
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
-- Copyright 2011-14 Paul Kulchenko, ZeroBrane LLC
|
||||
-- authors: Luxinia Dev (Eike Decker & Christoph Kubisch)
|
||||
---------------------------------------------------------
|
||||
|
||||
local ide = ide
|
||||
|
||||
ide.iofilters["GermanUtf8Ascii"] = {
|
||||
|
||||
@@ -32,9 +32,10 @@ ide.config.keymap = {
|
||||
[ID_SAVEAS] = "Alt-Shift-S",
|
||||
[ID_SAVEALL] = "",
|
||||
[ID_RECENTFILES] = "",
|
||||
[ID_RECENTFILESPREV] = "Ctrl-<",
|
||||
[ID_RECENTFILESNEXT] = "Ctrl->",
|
||||
[ID_RECENTFILESPREV] = "Ctrl-,",
|
||||
[ID_RECENTFILESNEXT] = "Ctrl-.",
|
||||
[ID_EXIT] = "Ctrl-Q",
|
||||
[ID_RECENTPROJECTSPREV] = "Ctrl-Shift-<",
|
||||
-- Edit menu
|
||||
[ID_CUT] = "Ctrl-X",
|
||||
[ID_COPY] = "Ctrl-C",
|
||||
@@ -48,10 +49,16 @@ ide.config.keymap = {
|
||||
[ID_COMMENT] = "Ctrl-U",
|
||||
[ID_FOLD] = "F12",
|
||||
[ID_CLEARDYNAMICWORDS] = "",
|
||||
[ID_REINDENT] = "Ctrl-I",
|
||||
[ID_BOOKMARKTOGGLE] = "Ctrl-F2",
|
||||
[ID_BOOKMARKNEXT] = "F2",
|
||||
[ID_BOOKMARKPREV] = "Shift-F2",
|
||||
-- Search menu
|
||||
[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",
|
||||
@@ -64,6 +71,9 @@ ide.config.keymap = {
|
||||
[ID_VIEWCALLSTACK] = "Ctrl-Shift-S",
|
||||
[ID_VIEWDEFAULTLAYOUT] = "",
|
||||
[ID_VIEWFULLSCREEN] = "Ctrl-Shift-A",
|
||||
[ID_ZOOMRESET] = "Ctrl-0",
|
||||
[ID_ZOOMIN] = "Ctrl-+",
|
||||
[ID_ZOOMOUT] = "Ctrl--",
|
||||
-- Project menu
|
||||
[ID_RUN] = "F6",
|
||||
[ID_RUNNOW] = "Ctrl-F6",
|
||||
@@ -99,5 +109,21 @@ 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"},
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
-- Copyright (C) Paul Kulchenko 2011-2012
|
||||
-- Copyright 2011-14 Paul Kulchenko, ZeroBrane LLC
|
||||
-- styles for comment markup
|
||||
---------------------------------------------------------
|
||||
|
||||
local MD_MARK_ITAL = '_' -- italic
|
||||
local MD_MARK_BOLD = '**' -- bold
|
||||
@@ -14,7 +15,7 @@ local MD_MARK_MARK = ' ' -- separator
|
||||
local MD_LINK_NEWWINDOW = '+' -- indicator to open a new window for links
|
||||
local markup = {
|
||||
[MD_MARK_BOXD] = {st=25, fg={127,0,127}, b=true},
|
||||
[MD_MARK_CODE] = {st=26, fg={127,127,127}, fs=9},
|
||||
[MD_MARK_CODE] = {st=26, fg={127,127,127}, fs=10},
|
||||
[MD_MARK_HEAD] = {st=27, fn="Lucida Console", b=true},
|
||||
[MD_MARK_LINK] = {st=28, u=true, hs={32,32,127}},
|
||||
[MD_MARK_BOLD] = {st=29, b=true},
|
||||
@@ -31,7 +32,8 @@ function MarkupAddStyles(styles)
|
||||
local style = styles[key] or {}
|
||||
-- copy all style features by value
|
||||
for feature in pairs(value) do
|
||||
style[feature] = style[feature] or value[feature] end
|
||||
style[feature] = style[feature] or value[feature]
|
||||
end
|
||||
style.fg = style.fg or comment.fg
|
||||
style.bg = style.bg or comment.bg
|
||||
styles[key] = style
|
||||
@@ -94,6 +96,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 +124,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
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
-- Copyright 2011-14 Paul Kulchenko, ZeroBrane LLC
|
||||
-- authors: Lomtik Software (J. Winwood & John Labenski)
|
||||
-- Luxinia Dev (Eike Decker & Christoph Kubisch)
|
||||
---------------------------------------------------------
|
||||
|
||||
local ide = ide
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Create the Edit menu and attach the callback functions
|
||||
@@ -8,7 +10,7 @@ local ide = ide
|
||||
local frame = ide.frame
|
||||
local menuBar = frame.menuBar
|
||||
|
||||
local editMenu = wx.wxMenu{
|
||||
local editMenu = wx.wxMenu {
|
||||
{ ID_CUT, TR("Cu&t")..KSC(ID_CUT), TR("Cut selected text to clipboard") },
|
||||
{ ID_COPY, TR("&Copy")..KSC(ID_COPY), TR("Copy selected text to clipboard") },
|
||||
{ ID_PASTE, TR("&Paste")..KSC(ID_PASTE), TR("Paste text from the clipboard") },
|
||||
@@ -21,68 +23,72 @@ local editMenu = wx.wxMenu{
|
||||
{ ID_AUTOCOMPLETE, TR("Complete &Identifier")..KSC(ID_AUTOCOMPLETE), TR("Complete the current identifier") },
|
||||
{ ID_AUTOCOMPLETEENABLE, TR("Auto Complete Identifiers")..KSC(ID_AUTOCOMPLETEENABLE), TR("Auto complete while typing"), wx.wxITEM_CHECK },
|
||||
{ },
|
||||
{ ID_COMMENT, TR("C&omment/Uncomment")..KSC(ID_COMMENT), TR("Comment or uncomment current or selected lines") },
|
||||
{ },
|
||||
{ ID_FOLD, TR("&Fold/Unfold All")..KSC(ID_FOLD), TR("Fold or unfold all code folds") },
|
||||
{ ID_CLEARDYNAMICWORDS, TR("Clear &Dynamic Words")..KSC(ID_CLEARDYNAMICWORDS), TR("Resets the dynamic word list for autocompletion") },
|
||||
{ ID_SORT, TR("&Sort")..KSC(ID_SORT), TR("Sort selected lines") },
|
||||
{ },
|
||||
}
|
||||
|
||||
local preferencesMenu = wx.wxMenu{
|
||||
{ID_PREFERENCESSYSTEM, TR("Settings: System")..KSC(ID_PREFERENCESSYSTEM)},
|
||||
{ID_PREFERENCESUSER, TR("Settings: User")..KSC(ID_PREFERENCESUSER)},
|
||||
}
|
||||
editMenu:Append(ID_PREFERENCES, TR("Preferences"), preferencesMenu)
|
||||
editMenu:Append(ID_SOURCE, TR("Source"), wx.wxMenu {
|
||||
{ ID_COMMENT, TR("&Comment/Uncomment")..KSC(ID_COMMENT), TR("Comment or uncomment current or selected lines") },
|
||||
{ ID_REINDENT, TR("Correct &Indentation")..KSC(ID_REINDENT), TR("Re-indent selected lines") },
|
||||
{ ID_FOLD, TR("&Fold/Unfold All")..KSC(ID_FOLD), TR("Fold or unfold all code folds") },
|
||||
{ ID_SORT, TR("&Sort")..KSC(ID_SORT), TR("Sort selected lines") },
|
||||
})
|
||||
editMenu:Append(ID_BOOKMARK, TR("Bookmark"), wx.wxMenu {
|
||||
{ ID_BOOKMARKTOGGLE, TR("Toggle Bookmark")..KSC(ID_BOOKMARKTOGGLE) },
|
||||
{ ID_BOOKMARKNEXT, TR("Go To Next Bookmark")..KSC(ID_BOOKMARKNEXT) },
|
||||
{ ID_BOOKMARKPREV, TR("Go To Previous Bookmark")..KSC(ID_BOOKMARKPREV) },
|
||||
})
|
||||
editMenu:AppendSeparator()
|
||||
editMenu:Append(ID_PREFERENCES, TR("Preferences"), wx.wxMenu {
|
||||
{ ID_PREFERENCESSYSTEM, TR("Settings: System")..KSC(ID_PREFERENCESSYSTEM) },
|
||||
{ ID_PREFERENCESUSER, TR("Settings: User")..KSC(ID_PREFERENCESUSER) },
|
||||
})
|
||||
menuBar:Append(editMenu, TR("&Edit"))
|
||||
|
||||
editMenu:Check(ID_AUTOCOMPLETEENABLE, ide.config.autocomplete)
|
||||
|
||||
local function getControlWithFocus()
|
||||
local editor = GetEditor()
|
||||
for _,e in pairs({frame.bottomnotebook.shellbox, frame.bottomnotebook.errorlog}) do
|
||||
local ctrl = e:FindFocus()
|
||||
if ctrl and
|
||||
(ctrl:GetId() == e:GetId()
|
||||
or ide.osname == 'Macintosh' and
|
||||
ctrl:GetParent():GetId() == e:GetId()) then editor = e end
|
||||
end
|
||||
return editor
|
||||
local function onUpdateUIEditorInFocus(event)
|
||||
event:Enable(GetEditorWithFocus(GetEditor()) ~= nil)
|
||||
end
|
||||
|
||||
function OnUpdateUIEditMenu(event)
|
||||
local editor = getControlWithFocus()
|
||||
local function onUpdateUIEditMenu(event)
|
||||
local editor = GetEditorWithFocus()
|
||||
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,
|
||||
local alwaysOn = {
|
||||
[ID_SELECTALL] = true,
|
||||
-- allow Cut and Copy commands as these work on a line if no selection
|
||||
[ID_COPY] = true, [ID_CUT] = 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
|
||||
menu_id == ID_UNDO and editor:CanUndo() or
|
||||
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'
|
||||
and menu_id == ID_SELECTALL then enable = false end
|
||||
event:Enable(enable)
|
||||
end
|
||||
|
||||
function OnEditMenu(event)
|
||||
local editor = getControlWithFocus()
|
||||
local function onEditMenu(event)
|
||||
local editor = GetEditorWithFocus()
|
||||
if editor == nil then event:Skip(); return end
|
||||
|
||||
-- if there is no editor, or if it's not the editor we care about,
|
||||
-- then allow normal processing to take place
|
||||
if editor == nil or
|
||||
(editor:FindFocus() and editor:FindFocus():GetId() ~= editor:GetId()) or
|
||||
editor:GetClassInfo():GetClassName() ~= 'wxStyledTextCtrl'
|
||||
then event:Skip(); return end
|
||||
if PackageEventHandle("onEditorAction", editor, event) == false then
|
||||
return
|
||||
end
|
||||
|
||||
local menu_id = event:GetId()
|
||||
local copytext
|
||||
if (menu_id == ID_CUT or menu_id == ID_COPY)
|
||||
and ide.wxver >= "2.9.5" and editor:GetSelections() > 1 then
|
||||
local main = editor:GetMainSelection()
|
||||
copytext = editor:GetTextRange(editor:GetSelectionNStart(main), editor:GetSelectionNEnd(main))
|
||||
for s = 0, editor:GetSelections()-1 do
|
||||
if copytext ~= editor:GetTextRange(editor:GetSelectionNStart(s), editor:GetSelectionNEnd(s)) then
|
||||
copytext = nil
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if menu_id == ID_CUT then
|
||||
if editor:GetSelectionStart() == editor:GetSelectionEnd()
|
||||
then editor:LineCut() else editor:Cut() end
|
||||
@@ -94,13 +100,36 @@ function OnEditMenu(event)
|
||||
elseif menu_id == ID_UNDO then editor:Undo()
|
||||
elseif menu_id == ID_REDO then editor:Redo()
|
||||
end
|
||||
|
||||
if copytext then editor:CopyText(#copytext, copytext) end
|
||||
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_COMMAND_MENU_SELECTED, onEditMenu)
|
||||
frame:Connect(event, wx.wxEVT_UPDATE_UI, onUpdateUIEditMenu)
|
||||
end
|
||||
|
||||
for _, event in pairs({
|
||||
ID_BOOKMARKTOGGLE, ID_BOOKMARKNEXT, ID_BOOKMARKPREV,
|
||||
ID_AUTOCOMPLETE, ID_SORT, ID_REINDENT, ID_SHOWTOOLTIP,
|
||||
}) do
|
||||
frame:Connect(event, wx.wxEVT_UPDATE_UI, onUpdateUIEditorInFocus)
|
||||
end
|
||||
|
||||
frame:Connect(ID_FOLD, wx.wxEVT_UPDATE_UI,
|
||||
function(event)
|
||||
local editor = GetEditorWithFocus(GetEditor())
|
||||
event:Enable(ide.config.editor.fold and editor ~= nil)
|
||||
end)
|
||||
|
||||
frame:Connect(ID_COMMENT, wx.wxEVT_UPDATE_UI,
|
||||
function(event)
|
||||
local editor = GetEditorWithFocus(GetEditor())
|
||||
event:Enable(editor ~= nil
|
||||
and pcall(function() return editor.spec end) and editor.spec
|
||||
and editor.spec.linecomment and true or false)
|
||||
end)
|
||||
|
||||
local function generateConfigMessage(type)
|
||||
return ([==[--[[--
|
||||
Use this file to specify %s preferences.
|
||||
@@ -141,19 +170,12 @@ frame:Connect(ID_SHOWTOOLTIP, wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
|
||||
EditorCallTip(editor, editor:GetCurrentPos())
|
||||
end)
|
||||
frame:Connect(ID_SHOWTOOLTIP, wx.wxEVT_UPDATE_UI,
|
||||
function (event) event:Enable(GetEditor() ~= nil) end)
|
||||
|
||||
frame:Connect(ID_AUTOCOMPLETE, wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
function (event)
|
||||
EditorAutoComplete(GetEditor())
|
||||
end)
|
||||
frame:Connect(ID_AUTOCOMPLETE, wx.wxEVT_UPDATE_UI, OnUpdateUIEditMenu)
|
||||
function (event) EditorAutoComplete(GetEditor()) end)
|
||||
|
||||
frame:Connect(ID_AUTOCOMPLETEENABLE, wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
function (event)
|
||||
ide.config.autocomplete = event:IsChecked()
|
||||
end)
|
||||
function (event) ide.config.autocomplete = event:IsChecked() end)
|
||||
|
||||
frame:Connect(ID_COMMENT, wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
function (event)
|
||||
@@ -215,28 +237,136 @@ 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)
|
||||
|
||||
local function processSelection(editor, func)
|
||||
local text = editor:GetSelectedText()
|
||||
local line = editor:GetCurrentLine()
|
||||
local posinline = editor:GetCurrentPos() - editor:PositionFromLine(line)
|
||||
if #text == 0 then
|
||||
editor:SelectAll()
|
||||
text = editor:GetSelectedText()
|
||||
end
|
||||
local wholeline = text:find('\n$')
|
||||
local buf = {}
|
||||
for line in string.gmatch(text..(wholeline and '' or '\n'), "(.-\r?\n)") do
|
||||
table.insert(buf, line)
|
||||
end
|
||||
if #buf > 0 then
|
||||
if func then func(buf) end
|
||||
-- add new line at the end if it was there
|
||||
local newtext = table.concat(buf, ''):gsub('(\r?\n)$', wholeline and '%1' or '')
|
||||
-- straightforward editor:ReplaceSelection() doesn't work reliably as
|
||||
-- it sometimes doubles the context when the entire file is selected.
|
||||
-- this seems like Scintilla issue, so use ReplaceTarget instead.
|
||||
-- Since this doesn't work with rectangular selection, which
|
||||
-- ReplaceSelection should handle (after wxwidgets 3.x upgrade), this
|
||||
-- will need to be revisited when ReplaceSelection is updated.
|
||||
if newtext ~= text then
|
||||
editor:TargetFromSelection()
|
||||
editor:ReplaceTarget(newtext)
|
||||
end
|
||||
end
|
||||
editor:GotoPosEnforcePolicy(math.min(
|
||||
editor:PositionFromLine(line)+posinline, editor:GetLineEndPosition(line)))
|
||||
end
|
||||
|
||||
frame:Connect(ID_SORT, wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
function (event) processSelection(GetEditor(), table.sort) end)
|
||||
|
||||
local function reIndent(editor, buf)
|
||||
local decindent, incindent = editor.spec.isdecindent, editor.spec.isincindent
|
||||
if not (decindent and incindent) then return end
|
||||
|
||||
local line = editor:LineFromPosition(editor:GetSelectionStart())
|
||||
local indent = 0
|
||||
local text = ''
|
||||
-- find the last non-empty line in the previous block (if any)
|
||||
for n = line-1, 1, -1 do
|
||||
indent = editor:GetLineIndentation(n)
|
||||
text = editor:GetLine(n)
|
||||
if text:match('[^\r\n]') then break end
|
||||
end
|
||||
|
||||
local ut = editor:GetUseTabs()
|
||||
local tw = ut and editor:GetTabWidth() or editor:GetIndent()
|
||||
|
||||
local indents = {}
|
||||
local isstatic = {}
|
||||
for line = 1, #buf+1 do
|
||||
local style = bit.band(editor:GetStyleAt(editor:PositionFromLine(line-1)), 31)
|
||||
-- don't reformat multi-line comments or strings
|
||||
isstatic[line] = editor.spec.iscomment[style] or editor.spec.isstring[style]
|
||||
if not isstatic[line] or line == 1 or not isstatic[line-1] then
|
||||
local closed, blockend = decindent(text)
|
||||
local opened = incindent(text)
|
||||
|
||||
-- ignore impact from initial block endings as they are already indented
|
||||
if line == 1 then blockend = 0 end
|
||||
|
||||
-- this only needs to be done for 2, #buf+1; do it and get out when done
|
||||
if line > 1 then indents[line-1] = indents[line-1] - tw * closed end
|
||||
if line > #buf then break end
|
||||
|
||||
indent = indent + tw * (opened - blockend)
|
||||
if indent < 0 then indent = 0 end
|
||||
end
|
||||
|
||||
indents[line] = indent
|
||||
text = buf[line]
|
||||
end
|
||||
|
||||
for line = 1, #buf do
|
||||
if not isstatic[line] then
|
||||
buf[line] = buf[line]:gsub("^[ \t]*",
|
||||
not buf[line]:match('%S') and ''
|
||||
or ut and ("\t"):rep(indents[line] / tw) or (" "):rep(indents[line]))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
frame:Connect(ID_REINDENT, wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
function (event)
|
||||
local editor = GetEditor()
|
||||
local buf = {}
|
||||
for line in string.gmatch(editor:GetSelectedText()..'\n', "(.-)\r?\n") do
|
||||
table.insert(buf, line)
|
||||
end
|
||||
if #buf > 0 then
|
||||
local newline
|
||||
if #(buf[#buf]) == 0 then newline = table.remove(buf) end
|
||||
table.sort(buf)
|
||||
-- add new line at the end if it was there
|
||||
if newline then table.insert(buf, newline) end
|
||||
editor:ReplaceSelection(table.concat(buf,"\n"))
|
||||
end
|
||||
processSelection(editor, function(buf) reIndent(editor, buf) end)
|
||||
end)
|
||||
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)
|
||||
function (event) FoldSome() end)
|
||||
|
||||
local BOOKMARK_MARKER = StylesGetMarker("bookmark")
|
||||
local BOOKMARK_MARKER_VALUE = 2^BOOKMARK_MARKER
|
||||
|
||||
local function bookmarkToggle()
|
||||
local editor = GetEditor()
|
||||
local line = editor:GetCurrentLine()
|
||||
local markers = editor:MarkerGet(line)
|
||||
if bit.band(markers, BOOKMARK_MARKER_VALUE) > 0 then
|
||||
editor:MarkerDelete(line, BOOKMARK_MARKER)
|
||||
else
|
||||
editor:MarkerAdd(line, BOOKMARK_MARKER)
|
||||
end
|
||||
end
|
||||
|
||||
local function bookmarkNext()
|
||||
local editor = GetEditor()
|
||||
local line = editor:MarkerNext(editor:GetCurrentLine()+1, BOOKMARK_MARKER_VALUE)
|
||||
if line == -1 then line = editor:MarkerNext(0, BOOKMARK_MARKER_VALUE) end
|
||||
if line ~= -1 then
|
||||
editor:GotoLine(line)
|
||||
editor:EnsureVisibleEnforcePolicy(line)
|
||||
end
|
||||
end
|
||||
|
||||
local function bookmarkPrev()
|
||||
local editor = GetEditor()
|
||||
local line = editor:MarkerPrevious(editor:GetCurrentLine()-1, BOOKMARK_MARKER_VALUE)
|
||||
if line == -1 then line = editor:MarkerPrevious(editor:GetLineCount(), BOOKMARK_MARKER_VALUE) end
|
||||
if line ~= -1 then
|
||||
editor:GotoLine(line)
|
||||
editor:EnsureVisibleEnforcePolicy(line)
|
||||
end
|
||||
end
|
||||
|
||||
frame:Connect(ID_BOOKMARKTOGGLE, wx.wxEVT_COMMAND_MENU_SELECTED, bookmarkToggle)
|
||||
frame:Connect(ID_BOOKMARKNEXT, wx.wxEVT_COMMAND_MENU_SELECTED, bookmarkNext)
|
||||
frame:Connect(ID_BOOKMARKPREV, wx.wxEVT_COMMAND_MENU_SELECTED, bookmarkPrev)
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
-- Copyright 2011-14 Paul Kulchenko, ZeroBrane LLC
|
||||
-- authors: Lomtik Software (J. Winwood & John Labenski)
|
||||
-- Luxinia Dev (Eike Decker & Christoph Kubisch)
|
||||
---------------------------------------------------------
|
||||
|
||||
local ide = ide
|
||||
local frame = ide.frame
|
||||
local menuBar = frame.menuBar
|
||||
@@ -16,16 +18,27 @@ local fileMenu = wx.wxMenu({
|
||||
{ ID_SAVEAS, TR("Save &As...")..KSC(ID_SAVEAS), TR("Save the current document to a file with a new name") },
|
||||
{ ID_SAVEALL, TR("Save A&ll")..KSC(ID_SAVEALL), TR("Save all open documents") },
|
||||
{ },
|
||||
-- placeholder for ID_RECENTFILES
|
||||
-- placeholder for ID_RECENTFILES and ID_RECENTPROJECTS
|
||||
{ },
|
||||
{ ID_EXIT, TR("E&xit")..KSC(ID_EXIT), TR("Exit program") }})
|
||||
menuBar:Append(fileMenu, TR("&File"))
|
||||
|
||||
local filehistorymenu = wx.wxMenu({})
|
||||
local filehistorymenu = wx.wxMenu({
|
||||
{ },
|
||||
{ ID_RECENTFILESCLEAR, TR("Clear Items")..KSC(ID_RECENTFILESCLEAR), TR("Clear items from this list") },
|
||||
})
|
||||
local filehistory = wx.wxMenuItem(fileMenu, ID_RECENTFILES,
|
||||
TR("Recent Files")..KSC(ID_RECENTFILES), TR("File history"), wx.wxITEM_NORMAL, filehistorymenu)
|
||||
fileMenu:Insert(8,filehistory)
|
||||
|
||||
local projecthistorymenu = wx.wxMenu({
|
||||
{ },
|
||||
{ ID_RECENTPROJECTSCLEAR, TR("Clear Items")..KSC(ID_RECENTPROJECTSCLEAR), TR("Clear items from this list") },
|
||||
})
|
||||
local projecthistory = wx.wxMenuItem(fileMenu, ID_RECENTPROJECTS,
|
||||
TR("Recent &Projects")..KSC(ID_RECENTPROJECTS), TR("Project history"), wx.wxITEM_NORMAL, projecthistorymenu)
|
||||
fileMenu:Insert(9,projecthistory)
|
||||
|
||||
do -- recent file history
|
||||
local iscaseinsensitive = wx.wxFileName("A"):SameAs(wx.wxFileName("a"))
|
||||
local function isSameAs(f1, f2)
|
||||
@@ -116,8 +129,11 @@ do -- recent file history
|
||||
end
|
||||
end
|
||||
|
||||
local items = 0
|
||||
updateRecentFiles = function (list)
|
||||
local items = filehistorymenu:GetMenuItemCount()
|
||||
-- protect against recent files menu not being present
|
||||
if not ide:FindMenuItem(ID_RECENTFILES) then return end
|
||||
|
||||
for i=1, #list do
|
||||
local file = list[i].filename
|
||||
local id = ID("file.recentfiles."..i)
|
||||
@@ -129,13 +145,14 @@ do -- recent file history
|
||||
filehistorymenu:FindItem(id):SetItemLabel(label)
|
||||
else -- need to add an item
|
||||
local item = wx.wxMenuItem(filehistorymenu, id, label, "")
|
||||
filehistorymenu:Append(item)
|
||||
filehistorymenu:Insert(i-1, item)
|
||||
frame:Connect(id, wx.wxEVT_COMMAND_MENU_SELECTED, loadRecent)
|
||||
end
|
||||
end
|
||||
for i=items, #list+1, -1 do -- delete the rest if the list got shorter
|
||||
filehistorymenu:Delete(filehistorymenu:FindItemByPosition(i-1))
|
||||
end
|
||||
items = #list -- update the number of items for the next refresh
|
||||
|
||||
-- enable if there are any recent files
|
||||
fileMenu:Enable(ID_RECENTFILES, #list > 0)
|
||||
@@ -152,6 +169,17 @@ do -- recent file history
|
||||
addFileHistory(filename)
|
||||
updateRecentFiles(filehistory)
|
||||
end
|
||||
|
||||
function FileRecentListUpdate(menu)
|
||||
local list = filehistory
|
||||
for i=#list, 1, -1 do
|
||||
local id = ID("file.recentfiles."..i)
|
||||
local label = list[i].filename
|
||||
local item = wx.wxMenuItem(menu, id, label, "")
|
||||
menu:Insert(0, item)
|
||||
ide.frame:Connect(id, wx.wxEVT_COMMAND_MENU_SELECTED, loadRecent)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
frame:Connect(ID_NEW, wx.wxEVT_COMMAND_MENU_SELECTED, function() return NewFile() end)
|
||||
@@ -202,6 +230,28 @@ frame:Connect(ID_CLOSE, wx.wxEVT_UPDATE_UI,
|
||||
|
||||
frame:Connect(ID_EXIT, wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
function (event)
|
||||
if not SaveOnExit(true) then return end
|
||||
frame:Close() -- this will trigger wxEVT_CLOSE_WINDOW
|
||||
end)
|
||||
|
||||
frame:Connect(ID_RECENTPROJECTSCLEAR, wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
function (event) FileTreeProjectListClear() end)
|
||||
|
||||
frame:Connect(ID_RECENTFILESCLEAR, wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
function (event)
|
||||
SetFileHistory({})
|
||||
local ed = ide:GetEditor()
|
||||
if ed then AddToFileHistory(ide:GetDocument(ed):GetFilePath()) end
|
||||
end)
|
||||
|
||||
local recentprojects = 0
|
||||
frame:Connect(ID_RECENTPROJECTS, wx.wxEVT_UPDATE_UI,
|
||||
function (event)
|
||||
recentprojects = FileTreeProjectListUpdate(projecthistorymenu, recentprojects)
|
||||
if not recentprojects then return end
|
||||
local pos = 1 -- add shortcut for the previous project (if any)
|
||||
if recentprojects > pos then
|
||||
local item = projecthistorymenu:FindItemByPosition(pos)
|
||||
item:SetItemLabel(item:GetItemLabelText()..KSC(ID_RECENTPROJECTSPREV))
|
||||
end
|
||||
event:Enable(recentprojects > 0)
|
||||
end)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user