├── .editorconfig
├── .gitignore
├── .jshintrc
├── CHANGELOG.md
├── LICENSE
├── README.md
├── appveyor.yml
├── img
├── run_command.gif
└── stata_kernel_example.gif
├── keymaps
└── stata-exec.cson
├── lib
├── main.js
└── sendCode.js
├── menus
└── stata-exec.cson
├── package-lock.json
└── package.json
/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig is awesome: https://EditorConfig.org
2 |
3 | # top-most EditorConfig file
4 | root = true
5 |
6 | # Defaults for all files
7 | [*]
8 | end_of_line = lf
9 | insert_final_newline = true
10 | charset = utf-8
11 | trim_trailing_whitespace = true
12 | indent_style = space
13 | indent_size = 4
14 |
15 | # 2 space indentation
16 | [*.{js,R,r,yml,yaml}]
17 | indent_size = 2
18 |
19 | # Tab indentation (no size specified)
20 | [Makefile]
21 | indent_style = tab
22 | trim_trailing_whitespace = false
23 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | npm-debug.log
3 | node_modules
4 | .ropeproject
5 |
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "esversion": 6,
3 | "node": true,
4 | "globals" : {
5 | "atom": false
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | ## [1.8.6] - 2018-10-30
4 |
5 | - Modify note about Stata Jupyter kernel in README.
6 |
7 | ## [1.8.5] - 2018-08-20
8 |
9 | - Add note about Stata Jupyter kernel to README.
10 |
11 | ## [1.8.4] - 2018-08-20
12 |
13 | - Add `Stata` as option in Mac executable list.
14 |
15 | ## [1.8.3] - 2018-08-07
16 |
17 | - Remove comments when sending paragraphs and programs.
18 |
19 | ## [1.8.2] - 2018-08-02
20 |
21 | - Fix running on Windows
22 |
23 | ## [1.8.1] - 2018-07-30
24 |
25 | - Fix batch end of line errors. #41
26 | - Fix menus
27 |
28 | ## [1.8.0] - 2018-07-30
29 |
30 | - Support multiple cursors. #34
31 | - Fix batch sending of code. #41
32 | - Rewrite much of package in better JavaScript.
33 |
34 | ## [1.7.0] - 2018-07-25
35 |
36 | - Support batch sending of code selection; run with `do`.
37 | - On Linux, print stdout and stderr of xdotool to console
38 | - On Linux, fix bug where xdotool (more likely xclip) would fail when the clipboard was empty, i.e. upon first logging in.
39 |
40 | ## [1.6.0] - 2018-07-24
41 |
42 | - Use xdotool instead of autokey on Linux
43 | - Improves paste speed, reliability; allows for pasting unicode characters
44 | - Allows you to type while the code is pasting
45 | - In future could create functionality to support two Stata windows at once
46 | - Important bugfixes for using xdotool
47 | - Search only for the first Stata window
48 | - Force ctrl to be not pressed when the program sends ctrl+v. Since the user usually is pressing ctrl to run the command, this is important. Otherwise all that is entered into Stata is v.
49 |
50 |
51 | ## [1.5.2] - 2018-06-01
52 |
53 | - Update keymaps so the package works within Dynamic Documents
54 |
55 | ## [1.5.1] - 2018-05-17
56 | - Require that `end` be on a line by itself to indicate the end of a program.
57 | This is to prevent false positives where the word "end" appears elsewhere.
58 |
59 | ## [1.5.0] - 2018-05-17
60 | - Update API to resemble Hydrogen's API (keeping current keyboard shortcuts)
61 | - Add `Run and Move Down` command, bound to shift-enter
62 | - Fix bug in Linux where sending a large selection pasted some text in Atom instead of Stata.
63 |
64 | ## [1.4.6] - 2018-03-23
65 | - Fix bug that prevented graph windows from opening
66 |
67 | ## [1.4.5] - 2018-03-22
68 | - Add final `\r` to code on Windows
69 |
70 | ## [1.4.4] - 2018-03-22
71 | - Remove `\r\n` when removing comments, not just `\n`, to support windows line endings
72 |
73 | ## [1.4.3] - 2018-03-09
74 | - On Windows, when opening a new Stata session, set Stata's working directory to current file's working directory
75 |
76 | ## [1.4.2] - 2018-03-09
77 | - Small additions to README
78 |
79 | ## [1.4.1] - 2018-03-09
80 | - Try loading winax in a try/catch clause
81 |
82 | ## [1.4.0] - 2018-03-09
83 | - Add Windows support!
84 |
85 | ## [1.3.2] - 2018-02-23
86 | - Add try-except clause in `linux/stata-exec.py` to hopefully work correctly on Arch Linux.
87 |
88 | ## [1.3.1] - 2018-01-31
89 | - Same as 1.3.0 but didn't publish correctly the first time
90 |
91 | ## [1.3.0] - 2018-01-31
92 | - Fix running of multiple lines with ///
93 |
94 | ## [1.2.1] - 2017-11-20
95 | - Fix bug that couldn't find removeComments
96 |
97 | ## [1.2.0] - 2017-11-20
98 | - Add linux support.
99 | - Remove comments for all methods of sending code, not just 'send-command'
100 | - Change warnings from "can't find function" to "can't find program"
101 |
102 | ## [1.1.2] - 2017-11-19
103 | - Fix comment removal to not touch comments in strings. Fixes https://github.com/kylebarron/stata-exec/issues/2
104 | - Thanks to https://stackoverflow.com/questions/24518020/comprehensive-regexp-to-remove-javascript-comments
105 |
106 | ## [1.1.1] - 2017-11-19
107 | - Add restriction that code sent through Applescript can be max 8192 characters. https://www.stata.com/automation/#list
108 | - Include a line with `program drop myProgram` if it comes before `program define myProgram` when sending a program to Stata.
109 |
110 | ## [1.1.0] - 2017-11-19
111 | - Add XQuartz support. This allows code to be run on macOS in a session of Stata running on a remote server.
112 |
113 | ## [1.0.3] - 2017-11-15
114 | - Fix the "Set Working Directory" command to use compound double quotes.
115 | - Refactor "Do Entire File" to use `addSlashes()`
116 | - Fix links in README.md; some other updates.
117 |
118 | ## [1.0.1] and [1.0.2] - 2017-11-13
119 | - No updates; issues getting atom.io to publish the package.
120 |
121 | ## [1.0.0] - 2017-11-13
122 | - Atom [stata-exec](https://atom.io/packages/stata-exec) package transferred to [@kylebarron](https://github.com/kylebarron) and hosted at https://github.com/kylebarron/stata-exec.
123 | - Ported from version 0.5.0 of [atom-r-exec](https://github.com/pimentel/atom-r-exec). All functionality ported:
124 | - cmd-enter: send selection or current line to Stata.
125 | - shift-cmd-d: send entire file to Stata. (File must be saved first. This runs do "/path/to/current/file")
126 | - shift-alt-p: send the previous command.
127 | - shift-cmd-c: change Stata's working directory to that of current file.
128 | - shift-cmd-g: send paragraph under current cursor. A paragraph is a region enclosed by whitespace.
129 | - shift-cmd-r: send program definition under current cursor. For example, all the lines in the below snippet would be sent to Stata:
130 |
131 | ## [0.2.0] - 2017-06-27
132 | - Original code created by [@nickeubank](https://github.com/nickeubank). Still in repository located at https://github.com/nickeubank/atom-stata-exec.
133 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Kyle Barron
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # stata-exec
2 |
3 | Send code to Stata from [Atom](https://atom.io). This package supports Windows, MacOS, and Linux.
4 |
5 | ---
6 |
7 | While `stata-exec` will still be supported, I suggest users use the new [Stata Jupyter Kernel](https://kylebarron.github.io/stata_kernel/) along with the [Hydrogen package](https://atom.io/packages/Hydrogen) instead. It can show Stata results inline and works with Windows, macOS, and Linux. _It is not necessary to install `stata-exec` to use `stata-kernel`._
8 |
9 | 
10 |
11 | ---
12 |
13 | 
14 |
15 | ## News
16 |
17 | - Version 1.7.0 supports batch sending of code selection with `Run Batch`.
18 | - Version 1.6.0 uses a new program on Linux to send code to Stata. It seems _way_ better; faster pasting and supports unicode characters.
19 |
20 | ## Installation
21 |
22 | In the terminal run `apm install stata-exec` or go to Settings > Install and search for `stata-exec`.
23 | This package depends on [`language-stata`](https://atom.io/packages/language-stata), which you should be prompted to install if needed.
24 |
25 | ### MacOS
26 |
27 | MacOS has no dependencies but you must select the flavor of Stata you own in the package's configuration. Learn more in the [configuration section](#configuration) below. Then head to the [usage section](#usage) for more details on running code.
28 |
29 | ### Windows
30 |
31 | This package can potentially work on Windows but is very hard to get right, so it's not officially supported. I would strongly recommend Windows users try [`stata_kernel`](https://kylebarron.github.io/stata_kernel/) which has a much easier installation process on Windows.
32 |
33 | Windows installation has a few steps, and I haven't been able to perfectly reproduce the working package on all computers. I hope to make this easier in the future, but for now this will have to do. Sadly, at this point **you need administrator privileges** to install this for Windows.
34 |
35 | 1. Make sure you've installed this package and `language-stata`. In the command prompt, run `apm install stata-exec language-stata` or go to Settings > Install and search for `stata-exec` and `language-stata`.
36 | 2. [Install this specific version of the program Node to your computer](https://nodejs.org/dist/v7.4.0/node-v7.4.0-x64.msi). Use the default installation settings.
37 | 3. Open up an administrator PowerShell (you can right click on the Windows icon at the bottom left and select "Windows PowerShell (Admin)") and type in:
38 |
39 | ```
40 | npm install --global --production windows-build-tools
41 | ```
42 | This took me 5-10 minutes to install. This is installing Python and other tools needed to install the package in the next step. When finished you should see a long list of names in a tree, like this:
43 |
44 | ```
45 | `-- windows-build-tools@2.2.1
46 | +-- chalk@2.3.2
47 | | +-- ansi-styles@3.2.1
48 | | | `-- color-convert@1.9.1
49 | | | `-- color-name@1.1.3
50 | ...
51 | ```
52 | 4. Open up Command Prompt (type `cmd` in the search bar in the dock, and it will be the first result) and type in:
53 |
54 | ```
55 | cd %USERPROFILE%\.atom\packages\stata-exec
56 | npm install winax --python=%USERPROFILE%\.windows-build-tools\python27\python.exe
57 | atom -v
58 | ```
59 |
60 | Then enter the following, where you need to replace `ELECTRON_VERSION` with the text following "Electron" in the output of `atom -v`.
61 |
62 | ```
63 | npm rebuild winax --runtime=electron --target=ELECTRON_VERSION --disturl=https://atom.io/download/atom-shell --build-from-source
64 | ```
65 |
66 | 5. [Link the Stata Automation library](https://www.stata.com/automation/#install). The following steps worked for me on Windows 10. The Stata executable is most likely in the folder `C:\Program Files (x86)\Stata15`.
67 |
68 | > 1. In the installation directory, right-click on the Stata executable, for example, StataSE.exe. Choose "Create Shortcut".
69 | > 2. Right-click on the newly created "Shortcut to StataSE.exe", choose "Property", and change the Target from "C:\Program Files\Stata13\StataSE.exe" to "C:\Program Files\Stata13\StataSE.exe" /Register. Click "OK".
70 | > 3. Right-click on the updated "Shortcut to StataSE.exe"; choose "Run as administrator"
71 |
72 | While you're doing that, add the path of the Stata executable to the "Stata Path" option in the settings.
73 |
74 | 6. Restart Atom.
75 |
76 | Now you can open up a Stata do-file and run code! See [Usage](#usage) for more details.
77 |
78 | ### Linux
79 |
80 | **Important**: Linux dependencies changed in version 1.6.0. Linux users must install [xdotool](https://github.com/jordansissel/xdotool) and [xclip](https://github.com/astrand/xclip).
81 |
82 | On Ubuntu:
83 | ```
84 | sudo apt install xdotool xclip
85 | ```
86 |
87 | ## Usage
88 |
89 | Code can be run using either the Command Palette or with keyboard shortcuts.
90 |
91 | To open the Command Palette, press cmd-shift-P / ctrl-shift-P, and then start typing `Stata Exec`. The available commands will be shown in the drop-down menu.
92 |
93 | The following are the default keyboard shortcuts (on macOS, use cmd instead of ctrl). Keyboard shortcuts can be personalized in your `keymap.cson` file. [More instructions here](http://flight-manual.atom.io/behind-atom/sections/keymaps-in-depth/).
94 |
95 | | Command | Default keyboard binding | Description |
96 | |-----------------------------|------------------|-----------------------------------------------------------------|
97 | | `Run` | ctrl-enter | Run selection or current line in Stata. |
98 | | `Run All` | shift-enter | Run selection or current line in Stata and move down. |
99 | | `Run Batch` | ctrl-alt-d | Run selection with `do` instead of interactively pasting commands. |
100 | | `Run And Move Down` | shift-ctrl-D | Run entire file in Stata. (This runs `do "/path/to/current/file"`) |
101 | | `Run Paragraph` | ctrl-alt-p | Run the previous command. |
102 | | `Run Previous Command` | shift-ctrl-C | Change Stata's working directory to that of current file. |
103 | | `Run Program` | shift-ctrl-G | Run paragraph under current cursor. A paragraph is a region enclosed by whitespace. |
104 | | `Set Working Directory` | shift-ctrl-R | Run program definition under current cursor. See note below. |
105 |
106 | For `Run Program`, if there exists `program drop` on the line before `program define`, the line including the former will be included in the selection. For example, all the lines in the below snippet would be sent to Stata:
107 | ```stata
108 | cap program drop myProgram
109 | program define myProgram
110 | // program contents
111 | end
112 | ```
113 |
114 | Note that `end` must be on a line by itself to be identified as the end of the program.
115 |
116 | ## Configuration
117 |
118 | All configuration can be done in the settings panel (Settings > Packages > stata-exec). The available options are listed below:
119 |
120 | - Stata Path (used for Windows only)
121 | - Absolute path to Stata executable. The default setting will most likely need to be changed to reflect your install location and Stata flavor.
122 | - Which App (used for macOS only)
123 | - Select **StataIC**, **StataSE**, or **StataMP** depending on which version of Stata you have.
124 | - Select **XQuartz** if you want to run selections in session of Stata on a remote Unix server. To set this up, you need to have Stata already open in XQuartz; Atom will not open it for you. In your terminal, you'll need to do something like `ssh username@host -Y`, likely followed by `xstata`. This package's commands to run the entire do file and set the working directory are not supported on XQuartz.
125 | - Advance Position
126 | - If checked, move cursor to the next line/paragraph after running the current line/paragraph.
127 | - Focus Window
128 | - If checked, bring the Stata window to focus when sending code.
129 | - Otherwise, code runs in the background and the screen remains focused on Atom.
130 | - Notifications
131 | - If checked, a pop-up notification will appear when a paragraph or function is not identified.
132 | - Skip Comments
133 | - If this and Advance Position are checked, after running a line the cursor will move to the next uncommented line.
134 | - Paste Speed (used for XQuartz only)
135 | - This value changes the amount of time the program waits between switching to the XQuartz window, pasting code, and sending "enter". The only way to send code to XQuartz is to use the clipboard, and the responsiveness of this process will depend on the speed of your internet connection. If the copy-pasting isn't working, try increasing the value. Decreasing the value will run your code faster. Value must be between 0.1 and 10.
136 |
137 | ## Notes
138 |
139 | ### Troubleshooting and Known Issues
140 | - _Run All_ doesn't run the last line of the do file.
141 | - Stata needs there to be a _newline_ character following the last line of text. Add an empty line to the end of the file and it'll work.
142 | - On Linux, the Stata GUI window must be the only program open with a window title of `Stata/`. If not, it appears the program will alternate between open Stata windows when pasting. xdotool seems to let me choose which Stata window to send text to, so maybe that could be put into a more useful function in the future.
143 |
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | environment:
2 | PYTHON: "C:\\Python27-x64"
3 | matrix:
4 | - atom_v: '1.30'
5 | node_v: '8.9.3'
6 | electron_v: '2.0.5'
7 | - atom_v: '1.29'
8 | node_v: '8.9.3'
9 | electron_v: '2.0.5'
10 | install:
11 | - ps: Install-Product node $env:node_v
12 | - npm install --global npm@latest
13 | - set PATH=%APPDATA%\\npm;%PATH%
14 | - npm install winax --python=%PYTHON%\\python.exe
15 | - npm rebuild winax --runtime=electron --target=%electron_v% --disturl=https://atom.io/download/atom-shell --build-from-source
16 | matrix:
17 | fast_finish: true
18 | build: off
19 | shallow_clone: true
20 | cache:
21 | - '%APPDATA%\npm-cache'
22 | artifacts:
23 | - path: "node_modules\\winax"
24 |
--------------------------------------------------------------------------------
/img/run_command.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kylebarron/stata-exec/436066cf3977a4dbca0b68e8efb1d9f21a9e6b3a/img/run_command.gif
--------------------------------------------------------------------------------
/img/stata_kernel_example.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kylebarron/stata-exec/436066cf3977a4dbca0b68e8efb1d9f21a9e6b3a/img/stata_kernel_example.gif
--------------------------------------------------------------------------------
/keymaps/stata-exec.cson:
--------------------------------------------------------------------------------
1 | # Keybindings require three things to be fully defined: A selector that is
2 | # matched against the focused element, the keystroke and the command to
3 | # execute.
4 | #
5 | # Below is a basic keybinding which registers on all platforms by applying to
6 | # the root workspace element.
7 |
8 | # For more detailed documentation see
9 | # https://atom.io/docs/latest/advanced/keymaps
10 |
11 | # eventually make it like R-box with cmd-enter
12 | # and have custom command palette to choose application
13 | # https://discuss.atom.io/t/custom-use-of-the-command-palette/15702/2
14 |
15 | # Ported from https://github.com/nteract/hydrogen/blob/master/keymaps/hydrogen.cson
16 | # Using .platform-darwin overrides default keybinding assignment
17 | '.platform-darwin atom-text-editor[data-grammar="source stata"]:not([mini])':
18 | 'shift-cmd-c': 'stata-exec:set-working-directory'
19 | 'cmd-enter': 'stata-exec:run'
20 | 'shift-enter': 'stata-exec:run-and-move-down'
21 | 'shift-cmd-d': 'stata-exec:run-all'
22 | 'cmd-alt-d': 'stata-exec:run-batch'
23 | 'shift-cmd-r': 'stata-exec:run-program'
24 | 'shift-cmd-g': 'stata-exec:run-paragraph'
25 | 'shift-alt-p': 'stata-exec:run-previous-command'
26 |
27 | 'atom-text-editor[data-grammar="source stata"]:not([mini])':
28 | 'shift-ctrl-c': 'stata-exec:set-working-directory'
29 | 'ctrl-enter': 'stata-exec:run'
30 | 'shift-enter': 'stata-exec:run-and-move-down'
31 | 'shift-ctrl-d': 'stata-exec:run-all'
32 | 'ctrl-alt-d': 'stata-exec:run-batch'
33 | 'shift-ctrl-r': 'stata-exec:run-program'
34 | 'shift-ctrl-g': 'stata-exec:run-paragraph'
35 | 'ctrl-alt-p': 'stata-exec:run-previous-command'
36 |
37 | '.platform-darwin atom-text-editor[data-grammar="source dyndoc md stata"]:not([mini])':
38 | 'shift-cmd-c': 'stata-exec:set-working-directory'
39 | 'cmd-enter': 'stata-exec:run'
40 | 'shift-enter': 'stata-exec:run-and-move-down'
41 | 'shift-cmd-d': 'stata-exec:run-all'
42 | 'cmd-alt-d': 'stata-exec:run-batch'
43 | 'shift-cmd-r': 'stata-exec:run-program'
44 | 'shift-cmd-g': 'stata-exec:run-paragraph'
45 | 'shift-alt-p': 'stata-exec:run-previous-command'
46 |
47 | 'atom-text-editor[data-grammar="source dyndoc md stata"]:not([mini])':
48 | 'shift-ctrl-c': 'stata-exec:set-working-directory'
49 | 'ctrl-enter': 'stata-exec:run'
50 | 'shift-enter': 'stata-exec:run-and-move-down'
51 | 'shift-ctrl-d': 'stata-exec:run-all'
52 | 'ctrl-alt-d': 'stata-exec:run-batch'
53 | 'shift-ctrl-r': 'stata-exec:run-program'
54 | 'shift-ctrl-g': 'stata-exec:run-paragraph'
55 | 'ctrl-alt-p': 'stata-exec:run-previous-command'
56 |
57 | '.platform-darwin atom-text-editor[data-grammar="source dyndoc latex stata"]:not([mini])':
58 | 'shift-cmd-c': 'stata-exec:set-working-directory'
59 | 'cmd-enter': 'stata-exec:run'
60 | 'shift-enter': 'stata-exec:run-and-move-down'
61 | 'shift-cmd-d': 'stata-exec:run-all'
62 | 'cmd-alt-d': 'stata-exec:run-batch'
63 | 'shift-cmd-r': 'stata-exec:run-program'
64 | 'shift-cmd-g': 'stata-exec:run-paragraph'
65 | 'shift-alt-p': 'stata-exec:run-previous-command'
66 |
67 | 'atom-text-editor[data-grammar="source dyndoc latex stata"]:not([mini])':
68 | 'shift-ctrl-c': 'stata-exec:set-working-directory'
69 | 'ctrl-enter': 'stata-exec:run'
70 | 'shift-enter': 'stata-exec:run-and-move-down'
71 | 'shift-ctrl-d': 'stata-exec:run-all'
72 | 'ctrl-alt-d': 'stata-exec:run-batch'
73 | 'shift-ctrl-r': 'stata-exec:run-program'
74 | 'shift-ctrl-g': 'stata-exec:run-paragraph'
75 | 'ctrl-alt-p': 'stata-exec:run-previous-command'
76 |
--------------------------------------------------------------------------------
/lib/main.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const { CompositeDisposable, Point, Range } = require('atom');
4 | const path = require('path');
5 | const fs = require('fs');
6 | const sendCode = require('./sendCode');
7 |
8 | const apps = {
9 | stataMP: 'StataMP',
10 | stata: 'Stata',
11 | stataIC: 'StataIC',
12 | stataSE: 'StataSE',
13 | xquartz: 'XQuartz'
14 | };
15 |
16 | module.exports = {
17 | config: {
18 | whichApp: {
19 | type: 'string',
20 | enum: [apps.stataMP, apps.stataSE, apps.stata, apps.stataIC, apps.xquartz],
21 | default: apps.stataSE,
22 | description: 'Which application to send code to. Only applicable for MacOS. The StataIC executable is currently named `Stata`, so try choosing that if you\'re having issues.',
23 | order: 2
24 | },
25 | advancePosition: {
26 | type: 'boolean',
27 | default: false,
28 | order: 4,
29 | description: 'Cursor advances to the next line after ' +
30 | 'sending the current line when there is no selection'
31 | },
32 | skipComments: {
33 | type: 'boolean',
34 | default: true,
35 | order: 5,
36 | description: 'When "advancePosition" is true, skip lines that contain ' +
37 | 'only comments'
38 | },
39 | focusWindow: {
40 | type: 'boolean',
41 | default: true,
42 | order: 3,
43 | description: 'After code is sent, bring focus to where it was sent'
44 | },
45 | pasteSpeed: {
46 | type: 'number',
47 | default: 1.0,
48 | minimum: 0.1,
49 | maximum: 10,
50 | order: 7,
51 | description: 'This is only applicable for XQuartz. This value changes the amount of time the program waits between switching to the XQuartz window, pasting code, and sending "enter". The only way to send code to XQuartz is to use the clipboard, and the responsiveness of sending code will depend on the speed of your internet connection. If the copy-pasting isn\'t working, try increasing the value. Decreasing the value will run your code faster. Value must be between 0.1 and 10.'
52 | },
53 | stataPath: {
54 | type: 'string',
55 | description: 'Absolute path to Stata executable. Only applicable for Windows.',
56 | default: 'C:\\Program Files (x86)\\Stata15\\StataSE-64.exe',
57 | order: 1,
58 | },
59 | allowSave: {
60 | type: 'boolean',
61 | default: true,
62 | description: 'Save file automatically before running "Run All"'
63 | }
64 | },
65 |
66 | subscriptions: null,
67 |
68 | activate(state) {
69 | this.subscriptions = new CompositeDisposable();
70 |
71 | this.subscriptions.add(atom.commands.add('atom-text-editor',
72 | 'stata-exec:run', () => this.run()));
73 | this.subscriptions.add(atom.commands.add('atom-text-editor',
74 | 'stata-exec:run-and-move-down', () => this.run(true)));
75 | this.subscriptions.add(atom.commands.add('atom-text-editor',
76 | 'stata-exec:run-previous-command', () => this.runPreviousCommand()));
77 | this.subscriptions.add(atom.commands.add('atom-text-editor',
78 | 'stata-exec:run-all', () => this.runAll()));
79 | this.subscriptions.add(atom.commands.add('atom-text-editor',
80 | 'stata-exec:run-batch', () => this.run(false, true)));
81 | this.subscriptions.add(atom.commands.add('atom-text-editor', 'stata-exec:run-paragraph', () => this.runParagraph()));
82 | this.subscriptions.add(atom.commands.add('atom-text-editor', 'stata-exec:run-program', () => this.runFunction()));
83 | return this.subscriptions.add(atom.commands.add('atom-text-editor',
84 | 'stata-exec:set-working-directory', () => this.setWorkingDirectory()));
85 | },
86 |
87 | deactivate() {
88 | return this.subscriptions.dispose();
89 | },
90 |
91 | _getEditorAndBuffer() {
92 | const editor = atom.workspace.getActiveTextEditor();
93 | const buffer = editor.getBuffer();
94 | return [editor, buffer];
95 | },
96 |
97 | runAll() {
98 | const whichApp = atom.config.get('stata-exec.whichApp');
99 | var msg = '';
100 | if (whichApp == "XQuartz") {
101 | this.error('Running entire do file not supported for XQuartz');
102 | return;
103 | }
104 |
105 | const [editor, buffer] = this._getEditorAndBuffer();
106 | if (atom.config.get('stata-exec.allowSave')) {
107 | editor.save();
108 | }
109 | const documentTitle = editor.getPath();
110 | if (!documentTitle) {
111 | this.error('Error: File not yet saved.');
112 | return;
113 | }
114 | const doFileCommand = `do \`"${documentTitle}"'`;
115 | return sendCode.send(doFileCommand);
116 | },
117 |
118 | run(advancePosition=false, batch=false) {
119 | const whichApp = atom.config.get('stata-exec.whichApp');
120 | const [editor, buffer] = this._getEditorAndBuffer();
121 | // we store the current position so that we can jump back to it later
122 | // (if the user wants to)
123 | const currentPosition = editor.getLastSelection().getScreenRange().end;
124 | const selections = this.getSelections();
125 | const texts = selections.texts;
126 |
127 | for (var i = 0; i < texts.length; i++) {
128 | if (batch) {
129 | this.runBatch(texts[i]);
130 | } else {
131 | // For interactive code (i.e. copy-pasted code) need to make sure there
132 | // are no block comments or ///.
133 | sendCode.send(this.removeComments(texts[i]));
134 | }
135 | }
136 |
137 | if (atom.config.get('stata-exec.advancePosition') === true) {
138 | advancePosition = true;
139 | }
140 | if (advancePosition && !selections.anySelection) {
141 | let nextPosition = this._findForward(this.nonEmptyLine, currentPosition.row + 1);
142 | if (nextPosition != null) {
143 | if (nextPosition == null) { nextPosition = [currentPosition + 1, 0]; }
144 | editor.setCursorScreenPosition(nextPosition);
145 | return editor.moveToFirstCharacterOfLine();
146 | }
147 | } else {
148 | if (!selections.anySelection) {
149 | return editor.setCursorScreenPosition(currentPosition);
150 | }
151 | }
152 | },
153 |
154 | runBatch(text) {
155 | var codepath = path.join(process.env.HOME, '.stata-exec_batch_code');
156 | if (process.platform == 'win32') {
157 | var eol = '\r\n'
158 | } else {
159 | var eol = '\n'
160 | }
161 | if (text.substr(text.length - 1) !== '\n') {
162 | text += eol;
163 | }
164 | fs.writeFile(codepath, text, function(err) {
165 | if(err) {
166 | return console.log(err);
167 | }
168 | console.log(`The batch code was saved to ${codepath}!`);
169 | sendCode.send(`do \`"${codepath}"'`);
170 | });
171 | },
172 |
173 | removeComments(text) {
174 | console.log('code with comments: ' + text);
175 | text = text.replace(/((["'])(?:\\[\s\S]|.)*?\2|(?:[^\w\s]|^)\s*\/(?![*\/])(?:\\.|\[(?:\\.|.)\]|.)*?\/(?=[gmiy]{0,4}\s*(?![*\/])(?:\W|$)))|\/\/\/.*?\r?\n\s*|\/\/.*?$|\/\*[\s\S]*?\*\//gm, '$1');
176 | // https://stackoverflow.com/questions/24518020/comprehensive-regexp-to-remove-javascript-comments
177 | // Using the "Final Boss Fight" at the bottom. Otherwise it fails on `di 5 / 5 // hello`
178 | // code = code.replace(';', '')
179 | if (process.platform == 'win32') {
180 | text = text + '\r';
181 | }
182 | console.log('code without comments: ' + text);
183 | return text;
184 | },
185 |
186 | runPreviousCommand() {
187 | const whichApp = atom.config.get('stata-exec.whichApp');
188 | return sendCode.send(sendCode.previousCommand);
189 | },
190 |
191 | getFunctionRange() {
192 | // gets the range of the closest function above the cursor.
193 | // if there is no (proper) function, return false
194 | const [editor, buffer] = this._getEditorAndBuffer();
195 | const currentPosition = editor.getCursorBufferPosition();
196 | // search for the simple function that looks something like:
197 | // label <- function(...) {
198 | // in case the current function definition is on the current line
199 | currentPosition.row += 1;
200 | const backwardRange = [0, currentPosition];
201 | const funRegex = new RegExp(/^\s*(pr(ogram|ogra|ogr|og|o)?)\s*(?!drop\s+)(de(fine|fin|fi|f)?)?\s*[A-Za-z_][A-Za-z0-9_]{0,31}/g);
202 | let foundStart = null;
203 | editor.backwardsScanInBufferRange(funRegex, backwardRange, function(result) {
204 | if (result.range.start.column === 0) {
205 | foundStart = result.range;
206 | return result.stop();
207 | }
208 | });
209 |
210 | if ((foundStart == null)) {
211 | console.error("Couldn't find the beginning of the program.");
212 | return null;
213 | }
214 |
215 | const dropRegex = new RegExp(/\s*pr(ogram|ogra|ogr|og|o)?\s+(drop)\s+[A-Za-z_][A-Za-z0-9_]{0,31}/g);
216 | const textPrevRow = editor.lineTextForBufferRow(foundStart.start.row - 1);
217 | if (dropRegex.test(textPrevRow) == true) {
218 | foundStart.start.row -= 1;
219 | }
220 |
221 | // now look for the end
222 | const numberOfLines = editor.getLineCount();
223 | const forwardRange = [foundStart.start, new Point(numberOfLines + 1, 0)];
224 |
225 | let foundEnd = null;
226 | editor.scanInBufferRange(/^\s*end\s*$/g, forwardRange, function(result) {
227 | if (result.range.start.column === 0) {
228 | foundEnd = result.range;
229 | return result.stop();
230 | }
231 | });
232 |
233 | if ((foundEnd == null)) {
234 | console.error("Couldn't find the end of the program.");
235 | return null;
236 | }
237 |
238 | // check if cursor is contained in range
239 | currentPosition.row -= 1;
240 | if ((foundStart.start.row <= currentPosition.row) &&
241 | (currentPosition.row <= foundEnd.start.row)) {
242 | return new Range(foundStart.start, foundEnd.end);
243 | } else {
244 | console.error("Couldn't find a program surrounding the current line.");
245 | console.error("start: ", foundStart);
246 | console.error("end: ", foundEnd);
247 | console.error("currentPosition: ", currentPosition);
248 | return null;
249 | }
250 | },
251 |
252 | runFunction() {
253 | const [editor, buffer] = this._getEditorAndBuffer();
254 | const whichApp = atom.config.get('stata-exec.whichApp');
255 |
256 | const range = this.getFunctionRange();
257 | if (range != null) {
258 | let code = editor.getTextInBufferRange(range);
259 | return sendCode.send(this.removeComments(code));
260 | } else {
261 | return this.Warning("Couldn't find program.");
262 | }
263 | },
264 |
265 | getSelections() {
266 | // returns an object with keys:
267 | // selection: the selection or line at which the cursor is present
268 | // anySelection: if true, the user made a selection.
269 | const [editor, buffer] = this._getEditorAndBuffer();
270 |
271 | let selections = editor.getSelectionsOrderedByBufferPosition();
272 | let texts = Array(selections.length);
273 | let anySelection = true;
274 |
275 | for (var i = 0; i < selections.length; i++) {
276 | var selection = selections[i];
277 | if (selection.getText() === '') {
278 | anySelection = false;
279 | const cursorPosition = selection.cursor.getBufferPosition().row;
280 | texts[i] = editor.lineTextForBufferRow(cursorPosition);
281 | } else {
282 | texts[i] = selection.getText();
283 | }
284 | }
285 |
286 | return { texts, anySelection };
287 | },
288 |
289 | error(message) {
290 | console.error(message);
291 | return atom.notifications.addError(message);
292 | },
293 |
294 | warning(message) {
295 | console.error(message);
296 | return atom.notifications.addWarning(message);
297 | },
298 |
299 | onlyWhitespace(str) {
300 | // returns true if string is only whitespace
301 | return str.replace(/\s/g, '').length === 0;
302 | },
303 |
304 | getCurrentParagraphRange() {
305 | let lineIndex;
306 | const [editor, buffer] = this._getEditorAndBuffer();
307 | const currentPosition = editor.getCursorBufferPosition().row;
308 |
309 | let currentLine = buffer.lineForRow(currentPosition);
310 |
311 | if (this.onlyWhitespace(currentLine)) {
312 | return null;
313 | }
314 |
315 | let startIndex = -1;
316 | // if we exhaust loop, then this paragraph begins at the first line
317 | if (currentPosition > 0) {
318 | let asc, start;
319 | for (start = currentPosition - 1, lineIndex = start, asc = start <= 0; asc ? lineIndex <= 0 : lineIndex >= 0; asc ? lineIndex++ : lineIndex--) {
320 | currentLine = buffer.lineForRow(lineIndex);
321 | if (this.onlyWhitespace(currentLine)) {
322 | startIndex = lineIndex;
323 | break;
324 | }
325 | }
326 | }
327 | startIndex += 1;
328 |
329 | let endIndex = editor.getLineCount();
330 | const numberOfLines = editor.getLineCount() - 1;
331 | if (currentPosition < (endIndex - 1)) {
332 | let asc1, end, start1;
333 | for (start1 = currentPosition + 1, lineIndex = start1, end = numberOfLines, asc1 = start1 <= end; asc1 ? lineIndex <= end : lineIndex >= end; asc1 ? lineIndex++ : lineIndex--) {
334 | currentLine = buffer.lineForRow(lineIndex);
335 | if (this.onlyWhitespace(currentLine)) {
336 | endIndex = lineIndex;
337 | break;
338 | }
339 | }
340 | }
341 | endIndex -= 1;
342 |
343 | const paragraphRange = new Range([startIndex, 0], [endIndex, buffer.lineLengthForRow(endIndex)]);
344 |
345 | return paragraphRange;
346 | },
347 |
348 | runParagraph() {
349 | const whichApp = atom.config.get('stata-exec.whichApp');
350 | const [editor, buffer] = this._getEditorAndBuffer();
351 | const paragraphRange = this.getCurrentParagraphRange();
352 |
353 | if (paragraphRange) {
354 | let code = editor.getTextInBufferRange(paragraphRange);
355 | sendCode.send(this.removeComments(code));
356 | const advancePosition = atom.config.get('stata-exec.advancePosition');
357 | if (advancePosition) {
358 | const currentPosition = editor.getLastSelection().getScreenRange().end;
359 | let nextPosition = this._findForward(this.nonEmptyLine, paragraphRange.end.row + 1);
360 | if (nextPosition != null) {
361 | if (nextPosition == null) { nextPosition = [currentPosition + 1, 0]; }
362 | editor.setCursorScreenPosition(nextPosition);
363 | return editor.moveToFirstCharacterOfLine();
364 | }
365 | }
366 | } else {
367 | return this.Warning('No paragraph at cursor.');
368 | }
369 | },
370 |
371 | nonEmptyLine(line) {
372 | const skipComments = atom.config.get('stata-exec.skipComments');
373 | let ret = true;
374 | if (skipComments) {
375 | ret = !/^\s*#/.test(line);
376 | }
377 | // a non empty line is a line that doesn't contain only a comment
378 | // and at least 1 character
379 | return ret && /\S/.test(line);
380 | },
381 |
382 | _findForward(searchFun, startPosition = null) {
383 | const editor = atom.workspace.getActiveTextEditor();
384 | const buffer = editor.getBuffer();
385 |
386 | if ((startPosition == null)) {
387 | startPosition = editor.getCursorBufferPosition().row;
388 | }
389 |
390 | let index = null;
391 | const numberOfLines = editor.getLineCount() - 1;
392 | if (startPosition >= numberOfLines) {
393 | return null;
394 | }
395 | for (let lineIndex = startPosition, end = numberOfLines, asc = startPosition <= end; asc ? lineIndex <= end : lineIndex >= end; asc ? lineIndex++ : lineIndex--) {
396 | const currentLine = buffer.lineForRow(lineIndex);
397 | if (searchFun(currentLine)) {
398 | index = lineIndex;
399 | break;
400 | }
401 | }
402 |
403 | if (index != null) {
404 | return [index, buffer.lineLengthForRow(index)];
405 | }
406 |
407 | return null;
408 | },
409 |
410 | setWorkingDirectory() {
411 | const whichApp = atom.config.get('stata-exec.whichApp');
412 | if (whichApp == "XQuartz") {
413 | this.Warning('Set Working Directory not supported for XQuartz');
414 | return;
415 | }
416 |
417 | // set the current working directory to the directory of
418 | // where the current file is
419 | const [editor, buffer] = this._getEditorAndBuffer();
420 | let cwd = editor.getPath();
421 | if (!cwd) {
422 | this.Warning('No current working directory (save the file first).');
423 | return;
424 | }
425 | cwd = cwd.substring(0, cwd.lastIndexOf('/'));
426 | cwd = `cd \`"${cwd}"'`;
427 |
428 | return sendCode.send(cwd);
429 | }
430 | };
431 |
--------------------------------------------------------------------------------
/lib/sendCode.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const { spawn } = require('child_process');
4 | const delay = require('delay');
5 | const path = require('path');
6 | const fs = require('fs');
7 | const runApplescript = require('run-applescript');
8 | const escapeString = require('escape-string-applescript');
9 |
10 | module.exports = {
11 | previousCommand: '',
12 | winax: null,
13 |
14 | send(text, batch=false) {
15 | console.log('entering sendCode function');
16 | this.previousCommand = text;
17 | switch (process.platform) {
18 | case 'darwin':
19 | return this.sendMac(text);
20 | case 'linux':
21 | return this.sendLinux(text);
22 | case 'win32':
23 | return this.sendWindows(text);
24 | default:
25 | return this.error('Unknown operating system.');
26 | }
27 | },
28 |
29 | error(message) {
30 | console.error(message);
31 | return atom.notifications.addError(message);
32 | },
33 |
34 | defineWinax(){
35 | console.log('requiring winax')
36 | const os = require('os');
37 | var winaxPath = os.homedir();
38 | winaxPath += "/.atom/packages/stata-exec/node_modules/winax";
39 | try {
40 | return require(winaxPath);
41 | } catch (err) {
42 | console.error(err);
43 | atom.notifications.addError('Winax not correctly installed');
44 | }
45 | },
46 |
47 | sendWindows(text) {
48 | if (text.length > 8192) {
49 | this.error('Code to send must be <= 8192 characters');
50 | return;
51 | }
52 |
53 | if (!this.winax) {
54 | this.winax = this.defineWinax();
55 | }
56 |
57 | if (this.con) {
58 | return this.con.DoCommandAsync(text);
59 | }
60 |
61 | spawn(atom.config.get('stata-exec.stataPath'), { stdio: 'ignore', detached: true }).unref();
62 | return delay(2000)
63 | .then(() => {
64 | try {
65 | this.con = new this.winax.Object("stata.StataOLEApp", { // jshint ignore:line
66 | activate: true,
67 | async: true,
68 | type: true
69 | });
70 | } catch(err) {
71 | console.error(err);
72 | if (err.message.includes('Invalid class string')) {
73 | return this.error('Registering stata failed');
74 | }
75 | }
76 | const editor = atom.workspace.getActiveTextEditor();
77 | var cwd = editor.getPath();
78 | var folderPath = cwd.substring(0, cwd.lastIndexOf('\\') + 1);
79 | this.con.DoCommandAsync('cd `"' + folderPath + '"\'');
80 | this.con.DoCommandAsync(text);
81 | });
82 | },
83 |
84 | sendMac(text) {
85 | text = escapeString(text);
86 | const whichApp = atom.config.get('stata-exec.whichApp');
87 | if (whichApp === 'XQuartz') {
88 | return this.sendXQuartz(text);
89 | }
90 |
91 | if (text.length > 8192) {
92 | this.error('Code to send must be <= 8192 characters');
93 | return;
94 | }
95 |
96 | const focusWindow = atom.config.get('stata-exec.focusWindow');
97 | var cmd = '';
98 | if (focusWindow) {
99 | cmd += `tell application "${whichApp}" to activate\n`;
100 | }
101 | cmd += `tell application "${whichApp}" to DoCommandAsync "${text}"`;
102 |
103 | runApplescript(cmd)
104 | .then(() => {
105 | console.log('Finished applescript');
106 | console.log('code: ', text);
107 | return console.log('Applescript: ', cmd);
108 | }).catch((err) => {
109 | console.error(err);
110 | console.error('code: ', text);
111 | return console.error('Applescript: ', cmd);
112 | });
113 | },
114 |
115 | sendLinux(text) {
116 | var exec = require('child_process').exec;
117 | // The `keyup ctrl` is the most important part of this
118 | //
119 | // The --clearmodifiers flag doesn't work great. By default, I have most of
120 | // the run keys bound with a `ctrl` key. I.e. to run a line of code you'd
121 | // type `ctrl+enter`. But when `ctrl` is held down by the user, running
122 | // `ctrl+v` pastes only `v`, and doesn't paste the clipboard. To prevent
123 | // against this, I use `keyup ctrl`, which forces the beginning position of
124 | // `ctrl` to be not pressed, regardless of what the user is doing.
125 | var cmd = `
126 | old_cb="$(xclip -o -selection clipboard)";
127 | this_window="$(xdotool getactivewindow)" &&
128 | stata_window="$(xdotool search --name --limit 1 "Stata/(IC|SE|MP)? 1[0-9]\.[0-9]")" &&
129 | cat ~/.stata-exec_code | xclip -i -selection clipboard &&
130 | xdotool \
131 | keyup ctrl shift \
132 | windowactivate --sync $stata_window \
133 | key --clearmodifiers --delay 100 ctrl+v Return \
134 | windowactivate --sync $this_window;
135 | printf "$old_cb" | xclip -i -selection clipboard`;
136 |
137 | var codepath = path.join(process.env.HOME, '.stata-exec_code');
138 | fs.writeFile(codepath, text, function(err) {
139 | if(err) {
140 | console.log(err);
141 | this.error('Home directory not writeable. Check permissions');
142 | return;
143 | }
144 | console.log('The file was saved!');
145 | exec(cmd, function(err, stdout, stderr) {
146 | console.log('stdout: ' + stdout);
147 | console.log('stderr: ' + stderr);
148 | if (err) throw err;
149 | });
150 | });
151 | },
152 |
153 | sendXQuartz(text) {
154 | const pasteSpeed = atom.config.get('stata-exec.pasteSpeed');
155 | const focusWindow = atom.config.get('stata-exec.focusWindow');
156 | var cmd = `
157 | set current_clipboard to the clipboard
158 | set the clipboard to ("${text}" as text)
159 | tell application "XQuartz" to activate
160 | delay 0.4 * ${pasteSpeed}
161 | tell application "System Events" to keystroke "v" using control down
162 | delay 0.9 * ${pasteSpeed}
163 | tell application "System Events" to keystroke return
164 | delay 0.1 * ${pasteSpeed}`;
165 | if (!focusWindow) {
166 | cmd += '\ntell application "Atom" to activate';
167 | }
168 | cmd += '\nset the clipboard to current_clipboard';
169 |
170 | runApplescript(cmd)
171 | .then(() => {
172 | console.log('Finished applescript');
173 | }).catch((err) => {
174 | console.error(err);
175 | console.error('code: ', text);
176 | return console.error('Applescript: ', cmd);
177 | });
178 | }
179 | };
180 |
--------------------------------------------------------------------------------
/menus/stata-exec.cson:
--------------------------------------------------------------------------------
1 | 'menu': [
2 | {
3 | 'label': 'Packages'
4 | 'submenu': [
5 | 'label': 'Stata-exec'
6 | 'submenu': [
7 | {
8 | 'label': 'Run'
9 | 'command': 'stata-exec:run'
10 | }, {
11 | 'label': 'Run and Move Down'
12 | 'command': 'stata-exec:run-and-move-down'
13 | }, {
14 | 'label': 'Run All'
15 | 'command': 'stata-exec:run-all'
16 | }, {
17 | 'label': 'Run Batch'
18 | 'command': 'stata-exec:run-batch'
19 | }, {
20 | 'label': 'Run Paragraph'
21 | 'command': 'stata-exec:run-paragraph'
22 | }, {
23 | 'label': 'Run Previous Command'
24 | 'command': 'stata-exec:run-previous-command'
25 | }, {
26 | 'label': 'Run Program'
27 | 'command': 'stata-exec:run-program'
28 | }, {
29 | 'label': 'Set Working Directory'
30 | 'command': 'stata-exec:set-working-directory'
31 | }
32 | ]
33 | ]
34 | }
35 | ]
36 |
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "stata-exec",
3 | "version": "1.8.6",
4 | "lockfileVersion": 1,
5 | "requires": true,
6 | "dependencies": {
7 | "atom-package-deps": {
8 | "version": "4.6.0",
9 | "resolved": "https://registry.npmjs.org/atom-package-deps/-/atom-package-deps-4.6.0.tgz",
10 | "integrity": "sha1-u4PwqXZWO0i+TquJ58hjHD7shI0=",
11 | "requires": {
12 | "atom-package-path": "^1.1.0",
13 | "sb-exec": "^3.0.1",
14 | "sb-fs": "^3.0.0",
15 | "semver": "^5.3.0"
16 | }
17 | },
18 | "atom-package-path": {
19 | "version": "1.1.0",
20 | "resolved": "https://registry.npmjs.org/atom-package-path/-/atom-package-path-1.1.0.tgz",
21 | "integrity": "sha1-tR/tvADnyM5SI9DYA9t6P09pYU8=",
22 | "requires": {
23 | "sb-callsite": "^1.1.2"
24 | }
25 | },
26 | "consistent-env": {
27 | "version": "1.3.1",
28 | "resolved": "https://registry.npmjs.org/consistent-env/-/consistent-env-1.3.1.tgz",
29 | "integrity": "sha1-9oI018afxt2WVviuI0Kc4EmbZfs=",
30 | "requires": {
31 | "lodash.uniq": "^4.5.0"
32 | }
33 | },
34 | "cross-spawn": {
35 | "version": "6.0.5",
36 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
37 | "integrity": "sha1-Sl7Hxk364iw6FBJNus3uhG2Ay8Q=",
38 | "requires": {
39 | "nice-try": "^1.0.4",
40 | "path-key": "^2.0.1",
41 | "semver": "^5.5.0",
42 | "shebang-command": "^1.2.0",
43 | "which": "^1.2.9"
44 | }
45 | },
46 | "delay": {
47 | "version": "2.0.0",
48 | "resolved": "https://registry.npmjs.org/delay/-/delay-2.0.0.tgz",
49 | "integrity": "sha1-kRLq3APk7H4AKXM3iW8nO72R+uU=",
50 | "requires": {
51 | "p-defer": "^1.0.0"
52 | }
53 | },
54 | "escape-string-applescript": {
55 | "version": "2.0.0",
56 | "resolved": "https://registry.npmjs.org/escape-string-applescript/-/escape-string-applescript-2.0.0.tgz",
57 | "integrity": "sha1-dgvKg4Zo5Aj+XuUs5CyvfLRsUnM="
58 | },
59 | "execa": {
60 | "version": "0.10.0",
61 | "resolved": "https://registry.npmjs.org/execa/-/execa-0.10.0.tgz",
62 | "integrity": "sha1-/0Vqj1P5D47MxxqW0Rvfx/CCy1A=",
63 | "requires": {
64 | "cross-spawn": "^6.0.0",
65 | "get-stream": "^3.0.0",
66 | "is-stream": "^1.1.0",
67 | "npm-run-path": "^2.0.0",
68 | "p-finally": "^1.0.0",
69 | "signal-exit": "^3.0.0",
70 | "strip-eof": "^1.0.0"
71 | }
72 | },
73 | "get-stream": {
74 | "version": "3.0.0",
75 | "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
76 | "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ="
77 | },
78 | "inherits": {
79 | "version": "2.0.1",
80 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz",
81 | "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE="
82 | },
83 | "is-stream": {
84 | "version": "1.1.0",
85 | "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
86 | "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ="
87 | },
88 | "is-utf8": {
89 | "version": "0.2.1",
90 | "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
91 | "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI="
92 | },
93 | "isexe": {
94 | "version": "2.0.0",
95 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
96 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
97 | },
98 | "lodash.uniq": {
99 | "version": "4.5.0",
100 | "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz",
101 | "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M="
102 | },
103 | "nice-try": {
104 | "version": "1.0.4",
105 | "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.4.tgz",
106 | "integrity": "sha1-2Tli9sUvLBVYwPvabVEoGfHv4cQ="
107 | },
108 | "npm-run-path": {
109 | "version": "2.0.2",
110 | "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
111 | "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=",
112 | "requires": {
113 | "path-key": "^2.0.0"
114 | }
115 | },
116 | "p-defer": {
117 | "version": "1.0.0",
118 | "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz",
119 | "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww="
120 | },
121 | "p-finally": {
122 | "version": "1.0.0",
123 | "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
124 | "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4="
125 | },
126 | "path": {
127 | "version": "0.12.7",
128 | "resolved": "https://registry.npmjs.org/path/-/path-0.12.7.tgz",
129 | "integrity": "sha1-1NwqUGxM4hl+tIHr/NWzbAFAsQ8=",
130 | "requires": {
131 | "process": "^0.11.1",
132 | "util": "^0.10.3"
133 | }
134 | },
135 | "path-key": {
136 | "version": "2.0.1",
137 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
138 | "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A="
139 | },
140 | "process": {
141 | "version": "0.11.10",
142 | "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
143 | "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI="
144 | },
145 | "run-applescript": {
146 | "version": "3.2.0",
147 | "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-3.2.0.tgz",
148 | "integrity": "sha1-c/s0zoXT3oB21RHqdnww1P38kYs=",
149 | "requires": {
150 | "execa": "^0.10.0"
151 | }
152 | },
153 | "sb-callsite": {
154 | "version": "1.1.2",
155 | "resolved": "https://registry.npmjs.org/sb-callsite/-/sb-callsite-1.1.2.tgz",
156 | "integrity": "sha1-KBkftm1k46PukghKlakPy1ECJDs="
157 | },
158 | "sb-exec": {
159 | "version": "3.1.0",
160 | "resolved": "https://registry.npmjs.org/sb-exec/-/sb-exec-3.1.0.tgz",
161 | "integrity": "sha1-NMxlCIoRZ1Lrcg/d7/ZtLC6V7FE=",
162 | "requires": {
163 | "consistent-env": "^1.2.0",
164 | "lodash.uniq": "^4.5.0",
165 | "sb-npm-path": "^2.0.0"
166 | }
167 | },
168 | "sb-fs": {
169 | "version": "3.0.0",
170 | "resolved": "https://registry.npmjs.org/sb-fs/-/sb-fs-3.0.0.tgz",
171 | "integrity": "sha1-+9zdMBDoChuOJ0kM7zNgZJdCA7g=",
172 | "requires": {
173 | "sb-promisify": "^2.0.1",
174 | "strip-bom-buf": "^1.0.0"
175 | }
176 | },
177 | "sb-memoize": {
178 | "version": "1.0.2",
179 | "resolved": "https://registry.npmjs.org/sb-memoize/-/sb-memoize-1.0.2.tgz",
180 | "integrity": "sha1-EoN1xi3bnMT/qQXQxaWXwZuurY4="
181 | },
182 | "sb-npm-path": {
183 | "version": "2.0.0",
184 | "resolved": "https://registry.npmjs.org/sb-npm-path/-/sb-npm-path-2.0.0.tgz",
185 | "integrity": "sha1-D2zCzzcd68p9k27Xa31MPMHrPVg=",
186 | "requires": {
187 | "sb-memoize": "^1.0.2",
188 | "sb-promisify": "^2.0.1"
189 | }
190 | },
191 | "sb-promisify": {
192 | "version": "2.0.2",
193 | "resolved": "https://registry.npmjs.org/sb-promisify/-/sb-promisify-2.0.2.tgz",
194 | "integrity": "sha1-QnelR1RIiqlnXYhuNU24lMm9yYE="
195 | },
196 | "semver": {
197 | "version": "5.5.0",
198 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz",
199 | "integrity": "sha1-3Eu8emyp2Rbe5dQ1FvAJK1j3uKs="
200 | },
201 | "shebang-command": {
202 | "version": "1.2.0",
203 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
204 | "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
205 | "requires": {
206 | "shebang-regex": "^1.0.0"
207 | }
208 | },
209 | "shebang-regex": {
210 | "version": "1.0.0",
211 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
212 | "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM="
213 | },
214 | "signal-exit": {
215 | "version": "3.0.2",
216 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
217 | "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0="
218 | },
219 | "strip-bom-buf": {
220 | "version": "1.0.0",
221 | "resolved": "https://registry.npmjs.org/strip-bom-buf/-/strip-bom-buf-1.0.0.tgz",
222 | "integrity": "sha1-HLRar1dTD0yvhsf3UXnSyaUd1XI=",
223 | "requires": {
224 | "is-utf8": "^0.2.1"
225 | }
226 | },
227 | "strip-eof": {
228 | "version": "1.0.0",
229 | "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
230 | "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8="
231 | },
232 | "util": {
233 | "version": "0.10.3",
234 | "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz",
235 | "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=",
236 | "requires": {
237 | "inherits": "2.0.1"
238 | }
239 | },
240 | "which": {
241 | "version": "1.3.1",
242 | "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
243 | "integrity": "sha1-pFBD1U9YBTFtqNYvn1CRjT2nCwo=",
244 | "requires": {
245 | "isexe": "^2.0.0"
246 | }
247 | },
248 | "winax": {
249 | "version": "1.0.13",
250 | "resolved": "https://registry.npmjs.org/winax/-/winax-1.0.13.tgz",
251 | "integrity": "sha512-yMUIhAclAxtqIxGpnXvrbPiuXce71RVttHRLqhu77vC0Wl1tZxTyr5gosHewmpxklgsxOeqsZEmAZbppfL6vOQ==",
252 | "optional": true
253 | }
254 | }
255 | }
256 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "stata-exec",
3 | "main": "./lib/main.js",
4 | "version": "1.8.6",
5 | "description": "Send code to Stata from Atom",
6 | "activationCommands": {
7 | "atom-text-editor": [
8 | "stata-exec:run",
9 | "stata-exec:run-all",
10 | "stata-exec:run-and-move-down",
11 | "stata-exec:run-batch",
12 | "stata-exec:run-paragraph",
13 | "stata-exec:run-previous-command",
14 | "stata-exec:run-program",
15 | "stata-exec:set-working-directory"
16 | ]
17 | },
18 | "repository": "https://github.com/kylebarron/stata-exec",
19 | "bugs": {
20 | "url": "https://github.com/kylebarron/stata-exec/issues"
21 | },
22 | "keywords": [
23 | "Stata"
24 | ],
25 | "license": "MIT",
26 | "engines": {
27 | "atom": ">1.0.0"
28 | },
29 | "package-deps": [
30 | "language-stata"
31 | ],
32 | "optionalDependencies": {
33 | "winax": "1.0.13"
34 | },
35 | "dependencies": {
36 | "atom-package-deps": "4.6.0",
37 | "delay": "^2.0.0",
38 | "escape-string-applescript": "^2.0.0",
39 | "path": "0.12.7",
40 | "run-applescript": "^3.2.0"
41 | }
42 | }
43 |
--------------------------------------------------------------------------------