tty-editor 0.3.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/CHANGELOG.md +48 -0
- data/README.md +167 -27
- data/lib/tty-editor.rb +1 -3
- data/lib/tty/editor.rb +172 -99
- data/lib/tty/editor/version.rb +3 -1
- metadata +24 -68
- data/.gitignore +0 -9
- data/.rspec +0 -3
- data/.travis.yml +0 -24
- data/CODE_OF_CONDUCT.md +0 -49
- data/Gemfile +0 -8
- data/Rakefile +0 -10
- data/appveyor.yml +0 -23
- data/bin/console +0 -14
- data/bin/setup +0 -8
- data/examples/basic.rb +0 -7
- data/examples/choices.rb +0 -9
- data/examples/empty.rb +0 -5
- data/examples/env.rb +0 -7
- data/examples/tempfile.rb +0 -7
- data/tasks/console.rake +0 -10
- data/tasks/coverage.rake +0 -11
- data/tasks/spec.rake +0 -29
- data/tty-editor.gemspec +0 -30
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 43382f86c223e305662a67b003a4337ce5946adaee09dcd48879714a91e45eae
|
4
|
+
data.tar.gz: fd58b6084c4cbedd605c09ce30fca817ea7f4d467e32ddfd558e3c7eb972f0a4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 31385f2ece1195d0c3801e495830c182f6808050c510ae83f3c78f48117a6a6a088ffce3177ea5283507a7e67cc235f6e580261e73ce03d0916044eeaeed0209
|
7
|
+
data.tar.gz: ddf5f4e74879e30a641ca4d3c7af06ffb0b7e36f8dd989915d599b283855e1fee77843d4788dd60eb7be93b1ef47b77285abb4a06b60528a36aefae75717dead
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,48 @@
|
|
1
1
|
# Change log
|
2
2
|
|
3
|
+
## [v0.6.0] - 2020-09-22
|
4
|
+
|
5
|
+
### Added
|
6
|
+
* Add ability to edit multiple files
|
7
|
+
* Add ability to configure input and output
|
8
|
+
* Add :raise_on_failure configuration option to control editor failure to run
|
9
|
+
* Add :show_menu configuration option to disable editor menu choice
|
10
|
+
* Add :prompt to configure an editor choice menu prompt
|
11
|
+
|
12
|
+
### Changed
|
13
|
+
* Change Editor#exist? to use direct path env var search
|
14
|
+
* Change Editor#new to stop accepting filename and text arguments
|
15
|
+
* Change Editor#new to select available text editors
|
16
|
+
* Change Editor#open to accept keyword arguments
|
17
|
+
* Change to stop raising when editor command cannot be run and return false instead
|
18
|
+
* Remove tty-which dependency
|
19
|
+
* Update tty-prompt dependency
|
20
|
+
|
21
|
+
### Fixed
|
22
|
+
* Fix to allow setting editor commands with flags
|
23
|
+
|
24
|
+
## [v0.5.1] - 2019-08-06
|
25
|
+
|
26
|
+
### Changed
|
27
|
+
* Change to update tty-prompt dependency
|
28
|
+
* Change to relax bundler & rake version requirement
|
29
|
+
|
30
|
+
## [v0.5.0] - 2018-12-18
|
31
|
+
|
32
|
+
### Changed
|
33
|
+
* Change to update and relax tty-prompt & tty-which constraints
|
34
|
+
|
35
|
+
## [v0.4.1] - 2018-08-29
|
36
|
+
|
37
|
+
### Changed
|
38
|
+
* Update tty-prompt dependency
|
39
|
+
|
40
|
+
## [v0.4.0] - 2018-04-14
|
41
|
+
|
42
|
+
### Changed
|
43
|
+
* Update tty-prompt dependency
|
44
|
+
* Change to freeze all strings
|
45
|
+
|
3
46
|
## [v0.3.0] - 2018-01-06
|
4
47
|
|
5
48
|
### Changed
|
@@ -41,6 +84,11 @@
|
|
41
84
|
|
42
85
|
* Initial implementation and release
|
43
86
|
|
87
|
+
[v0.6.0]: https://github.com/piotrmurach/tty-editor/compare/v0.5.1...v0.6.0
|
88
|
+
[v0.5.1]: https://github.com/piotrmurach/tty-editor/compare/v0.5.0...v0.5.1
|
89
|
+
[v0.5.0]: https://github.com/piotrmurach/tty-editor/compare/v0.4.1...v0.5.0
|
90
|
+
[v0.4.1]: https://github.com/piotrmurach/tty-editor/compare/v0.4.0...v0.4.1
|
91
|
+
[v0.4.0]: https://github.com/piotrmurach/tty-editor/compare/v0.3.0...v0.4.0
|
44
92
|
[v0.3.0]: https://github.com/piotrmurach/tty-editor/compare/v0.2.1...v0.3.0
|
45
93
|
[v0.2.1]: https://github.com/piotrmurach/tty-editor/compare/v0.2.0...v0.2.1
|
46
94
|
[v0.2.0]: https://github.com/piotrmurach/tty-editor/compare/v0.1.2...v0.2.0
|
data/README.md
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
<div align="center">
|
2
|
+
<a href="https://ttytoolkit.org" target="_blank"><img width="130" src="https://github.com/piotrmurach/tty/raw/master/images/tty.png" alt="TTY Toolkit logo" /></a>
|
3
|
+
</div>
|
4
|
+
|
1
5
|
# TTY::Editor [][gitter]
|
2
6
|
|
3
7
|
[][gem]
|
@@ -24,7 +28,7 @@
|
|
24
28
|
Add this line to your application's Gemfile:
|
25
29
|
|
26
30
|
```ruby
|
27
|
-
gem
|
31
|
+
gem "tty-editor"
|
28
32
|
```
|
29
33
|
|
30
34
|
And then execute:
|
@@ -35,70 +39,206 @@ Or install it yourself as:
|
|
35
39
|
|
36
40
|
$ gem install tty-editor
|
37
41
|
|
38
|
-
##
|
42
|
+
## Contents
|
43
|
+
|
44
|
+
* [1. Usage](#1-usage)
|
45
|
+
* [2. API](#2-api)
|
46
|
+
* [2.1 new](#21-new)
|
47
|
+
* [2.1.1 :command](#211-command)
|
48
|
+
* [2.1.2 :env](#212-env)
|
49
|
+
* [2.1.3 :raise_on_failure](#213-raise_on_failure)
|
50
|
+
* [2.1.4 :prompt](#214-prompt)
|
51
|
+
* [2.2 open](#22-open)
|
52
|
+
|
53
|
+
## 1. Usage
|
54
|
+
|
55
|
+
To edit a file in a default text editor do:
|
56
|
+
|
57
|
+
```ruby
|
58
|
+
TTY::Editor.open("/path/to/file")
|
59
|
+
```
|
39
60
|
|
40
|
-
To edit
|
61
|
+
To edit text in a default editor:
|
41
62
|
|
42
63
|
```ruby
|
43
|
-
TTY::Editor.open(
|
64
|
+
TTY::Editor.open(text: "Some text")
|
44
65
|
```
|
45
66
|
|
46
|
-
|
67
|
+
You can also open multiple existing and/or new files:
|
47
68
|
|
48
69
|
```ruby
|
49
|
-
TTY::Editor.open(
|
70
|
+
TTY::Editor.open("file_1", "file_2", "new_file_3")
|
50
71
|
```
|
51
72
|
|
52
|
-
|
73
|
+
Note that the `VISUAL` or `EDITOR` shell environment variables take precedence when auto detecting available editors.
|
74
|
+
|
75
|
+
You can also set your preferred editor command(s) and ignore `VISUAL` and `EDITOR` as well as other user preferences:
|
53
76
|
|
54
77
|
```ruby
|
55
|
-
TTY::Editor.open(
|
78
|
+
TTY::Editor.open("/path/to/file", command: "vim -f")
|
56
79
|
```
|
57
80
|
|
58
|
-
|
81
|
+
When `VISUAL` or `EDITOR` are not specified, a selection menu will be presented to the user.
|
59
82
|
|
60
|
-
|
83
|
+
For example, if an user has `vim`, `emacs` and `code` editors available on their system, they will see the following menu:
|
61
84
|
|
62
|
-
|
85
|
+
```
|
86
|
+
# Select an editor?
|
87
|
+
# 1) vim
|
88
|
+
# 2) emacs
|
89
|
+
# 3) code
|
90
|
+
# Choose 1-2 [1]:
|
91
|
+
```
|
63
92
|
|
64
|
-
|
93
|
+
You can further customise this behaviour with [:prompt](#214-prompt).
|
94
|
+
|
95
|
+
## 2. API
|
96
|
+
|
97
|
+
### 2.1 new
|
98
|
+
|
99
|
+
Instantiation of an editor will trigger automatic search for available command-line editors:
|
65
100
|
|
66
101
|
```ruby
|
67
|
-
TTY::Editor.
|
102
|
+
editor = TTY::Editor.new
|
68
103
|
```
|
69
104
|
|
70
|
-
|
105
|
+
You can change default search with the `:command` keyword argument.
|
71
106
|
|
72
|
-
|
107
|
+
#### 2.1.1 :command
|
73
108
|
|
74
|
-
|
109
|
+
You can force to always use a specific editor by passing `:command` option:
|
75
110
|
|
76
111
|
```ruby
|
77
|
-
TTY::Editor.
|
112
|
+
editor = TTY::Editor.new(command: "vim")
|
78
113
|
```
|
79
114
|
|
80
|
-
|
115
|
+
Or you can specify multiple commands and give a user a choice:
|
116
|
+
|
117
|
+
```ruby
|
118
|
+
editor = TTY::Editor.new(command: ["vim", "emacs"])
|
119
|
+
```
|
120
|
+
|
121
|
+
The class-level `open` method accepts the same parameters:
|
81
122
|
|
82
123
|
```ruby
|
83
|
-
TTY::Editor.open(
|
124
|
+
TTY::Editor.open("/path/to/file", command: "vim")
|
84
125
|
```
|
85
126
|
|
86
|
-
|
127
|
+
#### 2.1.2 :env
|
87
128
|
|
88
|
-
|
129
|
+
Use `:env` key to forward environment variables to the text editor launch command:
|
89
130
|
|
90
|
-
|
131
|
+
```ruby
|
132
|
+
TTY::Editor.new(env: {"FOO" => "bar"})
|
133
|
+
```
|
134
|
+
|
135
|
+
The class-level `open` method accepts the same parameters:
|
91
136
|
|
92
137
|
```ruby
|
93
|
-
TTY::Editor.open(
|
138
|
+
TTY::Editor.open("/path/to/file", env: {"FOO" => "bar"})
|
94
139
|
```
|
95
140
|
|
96
|
-
|
141
|
+
#### 2.1.3 :raise_on_failure
|
97
142
|
|
98
|
-
|
143
|
+
By default when editor fails to open a `false` status is returned:
|
144
|
+
|
145
|
+
```ruby
|
146
|
+
TTY::Editor.open("/path/to/unknown/file") # => false
|
147
|
+
```
|
148
|
+
|
149
|
+
Alternatively, you can use `:raise_on_failure` to raise an error on failure to open a file.
|
150
|
+
|
151
|
+
The `TTY::Editor::CommandInvocationError` will be raised anytime an editor fails to open a file:
|
152
|
+
|
153
|
+
```ruby
|
154
|
+
editor = TTY::Editor.new(raise_on_failure: true)
|
155
|
+
editor.open("/path/to/unknown/file")
|
156
|
+
# => raises TTY::Editor::ComandInvocationError
|
157
|
+
```
|
158
|
+
|
159
|
+
#### 2.1.4 :prompt
|
160
|
+
|
161
|
+
When more than one editor is available and user hasn't specified their preferred choice via `VISUAL` or `EDITOR` variables, a selection menu is presented.
|
162
|
+
|
163
|
+
For example, when `vim`, `emacs` and `code` executable exists on the system, the following menu will be displayed:
|
164
|
+
|
165
|
+
```
|
166
|
+
# Select an editor?
|
167
|
+
# 1) vim
|
168
|
+
# 2) emacs
|
169
|
+
# 3) code
|
170
|
+
# Choose 1-2 [1]:
|
171
|
+
```
|
172
|
+
|
173
|
+
If you would like to change the menu prompt use `:prompt` keyword:
|
174
|
+
|
175
|
+
```ruby
|
176
|
+
editor = TTY::Editor.new(prompt: "Which one do you fancy?")
|
177
|
+
editor.open("/path/to/file")
|
178
|
+
```
|
179
|
+
|
180
|
+
This may produce the following in the terminal:
|
181
|
+
|
182
|
+
```
|
183
|
+
# Which one do you fancy?
|
184
|
+
# 1) vim
|
185
|
+
# 2) emacs
|
186
|
+
# 3) code
|
187
|
+
# Choose 1-2 [1]:
|
188
|
+
```
|
189
|
+
|
190
|
+
### 2.2 open
|
191
|
+
|
192
|
+
There is a class-level and instance-level `open` method. These are equivalent:
|
193
|
+
|
194
|
+
```ruby
|
195
|
+
editor = TTY::Editor.new
|
196
|
+
editor.open(...)
|
197
|
+
# or
|
198
|
+
TTY::Editor.open(...)
|
199
|
+
```
|
200
|
+
|
201
|
+
Creating `TTY::Editor` instance means that the search for a command editor will be performed only once. Then the editor command will be shared between invocations of `open` call.
|
202
|
+
|
203
|
+
Conversely, the class-level `open` method will search for an editor each time it is invoked.
|
204
|
+
|
205
|
+
The following examples of using the `open` method apply to both the instance and class level invocations.
|
206
|
+
|
207
|
+
If you wish to open an editor without giving a file or content do:
|
208
|
+
|
209
|
+
```ruby
|
210
|
+
TTY::Editor.open
|
211
|
+
```
|
212
|
+
|
213
|
+
To open a file, pass a path as an argument to `open`:
|
214
|
+
|
215
|
+
```ruby
|
216
|
+
TTY::Editor.open("../README.md")
|
217
|
+
# => true
|
218
|
+
```
|
219
|
+
|
220
|
+
When editor successfully opens a file or content then `true` is returned, `false` otherwise.
|
221
|
+
|
222
|
+
You can change this with `:raise_on_failure` keyword to raise a `TTY::Editor::CommandInvocation` error when an editor cannot be opened.
|
223
|
+
|
224
|
+
In order to open text content inside an editor use `:text` keyword like so:
|
225
|
+
|
226
|
+
```ruby
|
227
|
+
TTY::Editor.open(text: "Some text")
|
228
|
+
```
|
229
|
+
|
230
|
+
You can also provide filename that will be created with specified content before editor is opened:
|
231
|
+
|
232
|
+
```ruby
|
233
|
+
TTY::Editor.open("/path/to/new-file", text: "Some text")
|
234
|
+
```
|
235
|
+
|
236
|
+
If you open a filename with already existing content then the new content will be appended at the end of the file.
|
237
|
+
|
238
|
+
You can also open multiple existing and non-existing files providing them as consecutive arguments:
|
99
239
|
|
100
240
|
```ruby
|
101
|
-
TTY::Editor.open(
|
241
|
+
TTY::Editor.open("file_1", "file_2", "new_file_3")
|
102
242
|
```
|
103
243
|
|
104
244
|
## Development
|
@@ -117,4 +257,4 @@ The gem is available as open source under the terms of the [MIT License](http://
|
|
117
257
|
|
118
258
|
## Copyright
|
119
259
|
|
120
|
-
Copyright (c) 2017
|
260
|
+
Copyright (c) 2017 Piotr Murach. See LICENSE for further details.
|
data/lib/tty-editor.rb
CHANGED
data/lib/tty/editor.rb
CHANGED
@@ -1,40 +1,53 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require 'shellwords'
|
3
|
+
require "fileutils"
|
4
|
+
require "shellwords"
|
5
|
+
require "tempfile"
|
6
|
+
require "tty-prompt"
|
8
7
|
|
9
|
-
require_relative
|
8
|
+
require_relative "editor/version"
|
10
9
|
|
11
10
|
module TTY
|
12
11
|
# A class responsible for launching an editor
|
13
12
|
#
|
14
13
|
# @api public
|
15
14
|
class Editor
|
15
|
+
Error = Class.new(StandardError)
|
16
|
+
|
17
|
+
# Raised when user provides unnexpected or incorrect argument
|
18
|
+
InvalidArgumentError = Class.new(Error)
|
19
|
+
|
16
20
|
# Raised when command cannot be invoked
|
17
21
|
class CommandInvocationError < RuntimeError; end
|
18
22
|
|
19
23
|
# Raised when editor cannot be found
|
20
24
|
class EditorNotFoundError < RuntimeError; end
|
21
25
|
|
22
|
-
#
|
26
|
+
# List possible command line text editors
|
23
27
|
#
|
24
|
-
# @return [
|
28
|
+
# @return [Array[String]]
|
25
29
|
#
|
26
|
-
# @api
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
+
# @api public
|
31
|
+
EXECUTABLES = [
|
32
|
+
"nano -w", "notepad", "vim", "vi", "emacs",
|
33
|
+
"code", "subl -n -w", "mate -w", "atom",
|
34
|
+
"pico", "qe", "mg", "jed"
|
35
|
+
].freeze
|
30
36
|
|
31
|
-
# Check if
|
37
|
+
# Check if editor command exists
|
38
|
+
#
|
39
|
+
# @example
|
40
|
+
# exist?("vim") # => true
|
32
41
|
#
|
33
42
|
# @return [Boolean]
|
34
43
|
#
|
35
|
-
# @api
|
36
|
-
def self.
|
37
|
-
|
44
|
+
# @api private
|
45
|
+
def self.exist?(command)
|
46
|
+
exts = ENV.fetch("PATHEXT", "").split(::File::PATH_SEPARATOR)
|
47
|
+
ENV.fetch("PATH", "").split(::File::PATH_SEPARATOR).any? do |dir|
|
48
|
+
file = ::File.join(dir, command)
|
49
|
+
::File.exist?(file) || exts.any? { |ext| ::File.exist?("#{file}#{ext}") }
|
50
|
+
end
|
38
51
|
end
|
39
52
|
|
40
53
|
# Check editor from environment variables
|
@@ -43,90 +56,98 @@ module TTY
|
|
43
56
|
#
|
44
57
|
# @api public
|
45
58
|
def self.from_env
|
46
|
-
[ENV[
|
47
|
-
end
|
48
|
-
|
49
|
-
# List possible executable for editor command
|
50
|
-
#
|
51
|
-
# @return [Array[String]]
|
52
|
-
#
|
53
|
-
# @api public
|
54
|
-
def self.executables
|
55
|
-
['vim', 'vi', 'emacs', 'nano', 'nano-tiny', 'pico', 'mate -w']
|
59
|
+
[ENV["VISUAL"], ENV["EDITOR"]].compact
|
56
60
|
end
|
57
61
|
|
58
|
-
# Find available
|
62
|
+
# Find available text editors
|
59
63
|
#
|
60
64
|
# @param [Array[String]] commands
|
61
65
|
# the commands to use intstead of defaults
|
62
66
|
#
|
63
67
|
# @return [Array[String]]
|
68
|
+
# the existing editor commands
|
64
69
|
#
|
65
70
|
# @api public
|
66
71
|
def self.available(*commands)
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
72
|
+
execs = if !commands.empty?
|
73
|
+
commands.map(&:to_s)
|
74
|
+
elsif from_env.any?
|
75
|
+
[from_env.first]
|
76
|
+
else
|
77
|
+
EXECUTABLES
|
78
|
+
end
|
79
|
+
execs.compact.map(&:strip).reject(&:empty?).uniq
|
80
|
+
.select { |exec| exist?(exec.split.first) }
|
76
81
|
end
|
77
82
|
|
78
83
|
# Open file in system editor
|
79
84
|
#
|
80
85
|
# @example
|
81
|
-
# TTY::Editor.open(
|
86
|
+
# TTY::Editor.open("/path/to/filename")
|
82
87
|
#
|
83
|
-
# @
|
84
|
-
#
|
88
|
+
# @example
|
89
|
+
# TTY::Editor.open("file1", "file2", "file3")
|
90
|
+
#
|
91
|
+
# @example
|
92
|
+
# TTY::Editor.open(text: "Some text")
|
93
|
+
#
|
94
|
+
# @param [Array<String>] files
|
95
|
+
# the files to open in an editor
|
96
|
+
# @param [String] :command
|
97
|
+
# the editor command to use, by default auto detects
|
98
|
+
# @param [String] :text
|
99
|
+
# the text to edit in an editor
|
100
|
+
# @param [Hash] :env
|
101
|
+
# environment variables to forward to the editor
|
85
102
|
#
|
86
103
|
# @return [Object]
|
87
104
|
#
|
88
105
|
# @api public
|
89
|
-
def self.open(*
|
90
|
-
editor = new(
|
91
|
-
|
92
|
-
yield(editor) if block_given?
|
93
|
-
|
94
|
-
editor.open
|
106
|
+
def self.open(*files, text: nil, **options, &block)
|
107
|
+
editor = new(**options, &block)
|
108
|
+
editor.open(*files, text: text)
|
95
109
|
end
|
96
110
|
|
97
111
|
# Initialize an Editor
|
98
112
|
#
|
99
|
-
# @param [String]
|
100
|
-
# @param [Hash[Symbol]] options
|
101
|
-
# @option options [Hash] :command
|
113
|
+
# @param [String] :command
|
102
114
|
# the editor command to use, by default auto detects
|
103
|
-
# @
|
115
|
+
# @param [Hash] :env
|
104
116
|
# environment variables to forward to the editor
|
117
|
+
# @param [IO] :input
|
118
|
+
# the standard input
|
119
|
+
# @param [IO] :output
|
120
|
+
# the standard output
|
121
|
+
# @param [Boolean] :raise_on_failure
|
122
|
+
# whether or not raise on command failure, false by default
|
123
|
+
# @param [Boolean] :show_menu
|
124
|
+
# whether or not show commands menu, true by default
|
105
125
|
#
|
106
126
|
# @api public
|
107
|
-
def initialize(
|
108
|
-
|
109
|
-
|
110
|
-
@
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
@filename = tempfile_path(options[:content])
|
122
|
-
end
|
127
|
+
def initialize(command: nil, raise_on_failure: false, show_menu: true,
|
128
|
+
prompt: "Select an editor?", env: {},
|
129
|
+
input: $stdin, output: $stdout, &block)
|
130
|
+
@env = env
|
131
|
+
@command = nil
|
132
|
+
@input = input
|
133
|
+
@output = output
|
134
|
+
@raise_on_failure = raise_on_failure
|
135
|
+
@show_menu = show_menu
|
136
|
+
@prompt = prompt
|
137
|
+
|
138
|
+
block.(self) if block
|
139
|
+
|
140
|
+
command(*Array(command))
|
123
141
|
end
|
124
142
|
|
125
143
|
# Read or update environment vars
|
126
144
|
#
|
145
|
+
# @return [Hash]
|
146
|
+
#
|
127
147
|
# @api public
|
128
148
|
def env(value = (not_set = true))
|
129
149
|
return @env if not_set
|
150
|
+
|
130
151
|
@env = value
|
131
152
|
end
|
132
153
|
|
@@ -146,64 +167,116 @@ module TTY
|
|
146
167
|
execs = self.class.available(*commands)
|
147
168
|
if execs.empty?
|
148
169
|
raise EditorNotFoundError,
|
149
|
-
|
170
|
+
"could not find a text editor to use. Please specify $VISUAL or "\
|
171
|
+
"$EDITOR or install one of the following editors: " \
|
172
|
+
"#{EXECUTABLES.map { |ed| ed.split.first }.join(", ")}."
|
150
173
|
end
|
151
|
-
|
152
|
-
@command = TTY::Which.which(exec.to_s)
|
174
|
+
@command = choose_exec_from(execs)
|
153
175
|
end
|
154
176
|
|
177
|
+
# Run editor command in a shell
|
178
|
+
#
|
179
|
+
# @param [Array<String>] files
|
180
|
+
# the files to open in an editor
|
181
|
+
# @param [String] :text
|
182
|
+
# the text to edit in an editor
|
183
|
+
#
|
184
|
+
# @raise [TTY::CommandInvocationError]
|
185
|
+
#
|
186
|
+
# @return [Boolean]
|
187
|
+
# whether editor command suceeded or not
|
188
|
+
#
|
155
189
|
# @api private
|
156
|
-
def
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
190
|
+
def open(*files, text: nil)
|
191
|
+
validate_arguments(files, text)
|
192
|
+
text_written = false
|
193
|
+
|
194
|
+
filepaths = files.reduce([]) do |paths, filename|
|
195
|
+
if !::File.exist?(filename)
|
196
|
+
::File.write(filename, text || "")
|
197
|
+
text_written = true
|
198
|
+
end
|
199
|
+
paths + [filename]
|
200
|
+
end
|
201
|
+
|
202
|
+
if !text.nil? && !text_written
|
203
|
+
tempfile = create_tempfile(text)
|
204
|
+
filepaths << tempfile.path
|
162
205
|
end
|
206
|
+
|
207
|
+
run(filepaths)
|
208
|
+
ensure
|
209
|
+
tempfile.unlink if tempfile
|
163
210
|
end
|
164
211
|
|
165
|
-
|
212
|
+
private
|
213
|
+
|
214
|
+
# Run editor command with file arguments
|
215
|
+
#
|
216
|
+
# @param [Array<String>] filepaths
|
217
|
+
# the file paths to open in an editor
|
218
|
+
#
|
219
|
+
# @return [Boolean]
|
220
|
+
# whether command succeeded or not
|
166
221
|
#
|
167
222
|
# @api private
|
168
|
-
def
|
169
|
-
|
223
|
+
def run(filepaths)
|
224
|
+
command_path = "#{command} #{filepaths.shelljoin}"
|
225
|
+
status = system(env, *Shellwords.split(command_path))
|
226
|
+
if @raise_on_failure && !status
|
227
|
+
raise CommandInvocationError,
|
228
|
+
"`#{command_path}` failed with status: #{$? ? $?.exitstatus : nil}"
|
229
|
+
end
|
230
|
+
!!status
|
170
231
|
end
|
171
232
|
|
172
|
-
#
|
233
|
+
# Check if filename and text arguments are valid
|
173
234
|
#
|
174
|
-
# @
|
235
|
+
# @raise [InvalidArgumentError]
|
175
236
|
#
|
176
237
|
# @api private
|
177
|
-
def
|
178
|
-
|
238
|
+
def validate_arguments(files, text)
|
239
|
+
return if files.empty?
|
240
|
+
|
241
|
+
if files.all? { |file| ::File.exist?(file) } && !text.nil?
|
242
|
+
raise InvalidArgumentError,
|
243
|
+
"cannot give a path to an existing file and text at the same time."
|
244
|
+
elsif filename = files.find { |file| ::File.exist?(file) && !::FileTest.file?(file) }
|
245
|
+
raise InvalidArgumentError, "don't know how to handle `#{filename}`. " \
|
246
|
+
"Please provide a file path or text"
|
247
|
+
end
|
179
248
|
end
|
180
249
|
|
181
|
-
# Create tempfile with
|
250
|
+
# Create tempfile with text
|
182
251
|
#
|
183
|
-
# @param [String]
|
252
|
+
# @param [String] text
|
253
|
+
#
|
254
|
+
# @return [Tempfile]
|
184
255
|
#
|
185
|
-
# @return [String]
|
186
256
|
# @api private
|
187
|
-
def
|
188
|
-
tempfile = Tempfile.new(
|
189
|
-
tempfile <<
|
257
|
+
def create_tempfile(text)
|
258
|
+
tempfile = Tempfile.new("tty-editor")
|
259
|
+
tempfile << text
|
190
260
|
tempfile.flush
|
191
|
-
|
192
|
-
|
193
|
-
end
|
194
|
-
tempfile.path
|
261
|
+
tempfile.close
|
262
|
+
tempfile
|
195
263
|
end
|
196
264
|
|
197
|
-
#
|
265
|
+
# Render an editor selection prompt to the terminal
|
198
266
|
#
|
199
|
-
# @
|
267
|
+
# @return [String]
|
268
|
+
# the chosen editor
|
200
269
|
#
|
201
270
|
# @api private
|
202
|
-
def
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
271
|
+
def choose_exec_from(execs)
|
272
|
+
if @show_menu && execs.size > 1
|
273
|
+
prompt = TTY::Prompt.new(input: @input, output: @output, env: @env)
|
274
|
+
exec = prompt.enum_select(@prompt, execs)
|
275
|
+
@output.print(prompt.cursor.up + prompt.cursor.clear_line)
|
276
|
+
exec
|
277
|
+
else
|
278
|
+
execs[0]
|
279
|
+
end
|
207
280
|
end
|
208
281
|
end # Editor
|
209
282
|
end # TTY
|
data/lib/tty/editor/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tty-editor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Piotr Murach
|
8
8
|
autorequire:
|
9
|
-
bindir:
|
9
|
+
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-09-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: tty-prompt
|
@@ -16,62 +16,28 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 0.
|
19
|
+
version: '0.22'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 0.
|
26
|
+
version: '0.22'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - "~>"
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: 0.3.0
|
34
|
-
type: :runtime
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - "~>"
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: 0.3.0
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: bundler
|
28
|
+
name: rake
|
43
29
|
requirement: !ruby/object:Gem::Requirement
|
44
30
|
requirements:
|
45
31
|
- - ">="
|
46
32
|
- !ruby/object:Gem::Version
|
47
|
-
version:
|
48
|
-
- - "<"
|
49
|
-
- !ruby/object:Gem::Version
|
50
|
-
version: '2.0'
|
33
|
+
version: '0'
|
51
34
|
type: :development
|
52
35
|
prerelease: false
|
53
36
|
version_requirements: !ruby/object:Gem::Requirement
|
54
37
|
requirements:
|
55
38
|
- - ">="
|
56
39
|
- !ruby/object:Gem::Version
|
57
|
-
version:
|
58
|
-
- - "<"
|
59
|
-
- !ruby/object:Gem::Version
|
60
|
-
version: '2.0'
|
61
|
-
- !ruby/object:Gem::Dependency
|
62
|
-
name: rake
|
63
|
-
requirement: !ruby/object:Gem::Requirement
|
64
|
-
requirements:
|
65
|
-
- - "~>"
|
66
|
-
- !ruby/object:Gem::Version
|
67
|
-
version: '10.0'
|
68
|
-
type: :development
|
69
|
-
prerelease: false
|
70
|
-
version_requirements: !ruby/object:Gem::Requirement
|
71
|
-
requirements:
|
72
|
-
- - "~>"
|
73
|
-
- !ruby/object:Gem::Version
|
74
|
-
version: '10.0'
|
40
|
+
version: '0'
|
75
41
|
- !ruby/object:Gem::Dependency
|
76
42
|
name: rspec
|
77
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -86,41 +52,32 @@ dependencies:
|
|
86
52
|
- - "~>"
|
87
53
|
- !ruby/object:Gem::Version
|
88
54
|
version: '3.0'
|
89
|
-
description:
|
55
|
+
description: Open a file or text in a terminal text editor.
|
90
56
|
email:
|
91
|
-
-
|
57
|
+
- piotr@piotrmurach.com
|
92
58
|
executables: []
|
93
59
|
extensions: []
|
94
|
-
extra_rdoc_files:
|
60
|
+
extra_rdoc_files:
|
61
|
+
- README.md
|
62
|
+
- CHANGELOG.md
|
63
|
+
- LICENSE.txt
|
95
64
|
files:
|
96
|
-
- ".gitignore"
|
97
|
-
- ".rspec"
|
98
|
-
- ".travis.yml"
|
99
65
|
- CHANGELOG.md
|
100
|
-
- CODE_OF_CONDUCT.md
|
101
|
-
- Gemfile
|
102
66
|
- LICENSE.txt
|
103
67
|
- README.md
|
104
|
-
- Rakefile
|
105
|
-
- appveyor.yml
|
106
|
-
- bin/console
|
107
|
-
- bin/setup
|
108
|
-
- examples/basic.rb
|
109
|
-
- examples/choices.rb
|
110
|
-
- examples/empty.rb
|
111
|
-
- examples/env.rb
|
112
|
-
- examples/tempfile.rb
|
113
68
|
- lib/tty-editor.rb
|
114
69
|
- lib/tty/editor.rb
|
115
70
|
- lib/tty/editor/version.rb
|
116
|
-
|
117
|
-
- tasks/coverage.rake
|
118
|
-
- tasks/spec.rake
|
119
|
-
- tty-editor.gemspec
|
120
|
-
homepage: https://piotrmurach.github.io/tty
|
71
|
+
homepage: https://ttytoolkit.org
|
121
72
|
licenses:
|
122
73
|
- MIT
|
123
|
-
metadata:
|
74
|
+
metadata:
|
75
|
+
allowed_push_host: https://rubygems.org
|
76
|
+
bug_tracker_uri: https://github.com/piotrmurach/tty-editor/issues
|
77
|
+
changelog_uri: https://github.com/piotrmurach/tty-editor/blob/master/CHANGELOG.md
|
78
|
+
documentation_uri: https://www.rubydoc.info/gems/tty-editor
|
79
|
+
homepage_uri: https://ttytoolkit.org
|
80
|
+
source_code_uri: https://github.com/piotrmurach/tty-editor
|
124
81
|
post_install_message:
|
125
82
|
rdoc_options: []
|
126
83
|
require_paths:
|
@@ -136,9 +93,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
136
93
|
- !ruby/object:Gem::Version
|
137
94
|
version: '0'
|
138
95
|
requirements: []
|
139
|
-
|
140
|
-
rubygems_version: 2.5.1
|
96
|
+
rubygems_version: 3.1.2
|
141
97
|
signing_key:
|
142
98
|
specification_version: 4
|
143
|
-
summary:
|
99
|
+
summary: Open a file or text in a terminal text editor.
|
144
100
|
test_files: []
|
data/.gitignore
DELETED
data/.rspec
DELETED
data/.travis.yml
DELETED
@@ -1,24 +0,0 @@
|
|
1
|
-
---
|
2
|
-
language: ruby
|
3
|
-
sudo: false
|
4
|
-
cache: bundler
|
5
|
-
script: "bundle exec rake ci"
|
6
|
-
rvm:
|
7
|
-
- 2.0.0
|
8
|
-
- 2.1.10
|
9
|
-
- 2.2.8
|
10
|
-
- 2.3.6
|
11
|
-
- 2.4.3
|
12
|
-
- ruby-head
|
13
|
-
- jruby-9.1.7.0
|
14
|
-
- jruby-head
|
15
|
-
matrix:
|
16
|
-
allow_failures:
|
17
|
-
- rvm: ruby-head
|
18
|
-
- rvm: jruby-head
|
19
|
-
- rvm: jruby-9.1.7.0
|
20
|
-
fast_finish: true
|
21
|
-
branches:
|
22
|
-
only: master
|
23
|
-
notifications:
|
24
|
-
email: false
|
data/CODE_OF_CONDUCT.md
DELETED
@@ -1,49 +0,0 @@
|
|
1
|
-
# Contributor Code of Conduct
|
2
|
-
|
3
|
-
As contributors and maintainers of this project, and in the interest of
|
4
|
-
fostering an open and welcoming community, we pledge to respect all people who
|
5
|
-
contribute through reporting issues, posting feature requests, updating
|
6
|
-
documentation, submitting pull requests or patches, and other activities.
|
7
|
-
|
8
|
-
We are committed to making participation in this project a harassment-free
|
9
|
-
experience for everyone, regardless of level of experience, gender, gender
|
10
|
-
identity and expression, sexual orientation, disability, personal appearance,
|
11
|
-
body size, race, ethnicity, age, religion, or nationality.
|
12
|
-
|
13
|
-
Examples of unacceptable behavior by participants include:
|
14
|
-
|
15
|
-
* The use of sexualized language or imagery
|
16
|
-
* Personal attacks
|
17
|
-
* Trolling or insulting/derogatory comments
|
18
|
-
* Public or private harassment
|
19
|
-
* Publishing other's private information, such as physical or electronic
|
20
|
-
addresses, without explicit permission
|
21
|
-
* Other unethical or unprofessional conduct
|
22
|
-
|
23
|
-
Project maintainers have the right and responsibility to remove, edit, or
|
24
|
-
reject comments, commits, code, wiki edits, issues, and other contributions
|
25
|
-
that are not aligned to this Code of Conduct, or to ban temporarily or
|
26
|
-
permanently any contributor for other behaviors that they deem inappropriate,
|
27
|
-
threatening, offensive, or harmful.
|
28
|
-
|
29
|
-
By adopting this Code of Conduct, project maintainers commit themselves to
|
30
|
-
fairly and consistently applying these principles to every aspect of managing
|
31
|
-
this project. Project maintainers who do not follow or enforce the Code of
|
32
|
-
Conduct may be permanently removed from the project team.
|
33
|
-
|
34
|
-
This code of conduct applies both within project spaces and in public spaces
|
35
|
-
when an individual is representing the project or its community.
|
36
|
-
|
37
|
-
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
38
|
-
reported by contacting a project maintainer at [email]. All
|
39
|
-
complaints will be reviewed and investigated and will result in a response that
|
40
|
-
is deemed necessary and appropriate to the circumstances. Maintainers are
|
41
|
-
obligated to maintain confidentiality with regard to the reporter of an
|
42
|
-
incident.
|
43
|
-
|
44
|
-
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
45
|
-
version 1.3.0, available at
|
46
|
-
[http://contributor-covenant.org/version/1/3/0/][version]
|
47
|
-
|
48
|
-
[homepage]: http://contributor-covenant.org
|
49
|
-
[version]: http://contributor-covenant.org/version/1/3/0/
|
data/Gemfile
DELETED
data/Rakefile
DELETED
data/appveyor.yml
DELETED
@@ -1,23 +0,0 @@
|
|
1
|
-
---
|
2
|
-
install:
|
3
|
-
- SET PATH=C:\Ruby%ruby_version%\bin;%PATH%
|
4
|
-
- ruby --version
|
5
|
-
- gem --version
|
6
|
-
- bundle install
|
7
|
-
build: off
|
8
|
-
test_script:
|
9
|
-
- bundle exec rake ci
|
10
|
-
environment:
|
11
|
-
matrix:
|
12
|
-
- ruby_version: "193"
|
13
|
-
- ruby_version: "200"
|
14
|
-
- ruby_version: "200-x64"
|
15
|
-
- ruby_version: "21"
|
16
|
-
- ruby_version: "21-x64"
|
17
|
-
- ruby_version: "22"
|
18
|
-
- ruby_version: "22-x64"
|
19
|
-
- ruby_version: "23"
|
20
|
-
- ruby_version: "23-x64"
|
21
|
-
matrix:
|
22
|
-
allow_failures:
|
23
|
-
- ruby_version: "193"
|
data/bin/console
DELETED
@@ -1,14 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
require "bundler/setup"
|
4
|
-
require "tty/editor"
|
5
|
-
|
6
|
-
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
-
# with your gem easier. You can also use a different console, if you like.
|
8
|
-
|
9
|
-
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
-
# require "pry"
|
11
|
-
# Pry.start
|
12
|
-
|
13
|
-
require "irb"
|
14
|
-
IRB.start
|
data/bin/setup
DELETED
data/examples/basic.rb
DELETED
data/examples/choices.rb
DELETED
data/examples/empty.rb
DELETED
data/examples/env.rb
DELETED
data/examples/tempfile.rb
DELETED
data/tasks/console.rake
DELETED
data/tasks/coverage.rake
DELETED
data/tasks/spec.rake
DELETED
@@ -1,29 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
begin
|
4
|
-
require 'rspec/core/rake_task'
|
5
|
-
|
6
|
-
desc 'Run all specs'
|
7
|
-
RSpec::Core::RakeTask.new(:spec) do |task|
|
8
|
-
task.pattern = 'spec/{unit,integration}{,/*/**}/*_spec.rb'
|
9
|
-
end
|
10
|
-
|
11
|
-
namespace :spec do
|
12
|
-
desc 'Run unit specs'
|
13
|
-
RSpec::Core::RakeTask.new(:unit) do |task|
|
14
|
-
task.pattern = 'spec/unit{,/*/**}/*_spec.rb'
|
15
|
-
end
|
16
|
-
|
17
|
-
desc 'Run integration specs'
|
18
|
-
RSpec::Core::RakeTask.new(:integration) do |task|
|
19
|
-
task.pattern = 'spec/integration{,/*/**}/*_spec.rb'
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
rescue LoadError
|
24
|
-
%w[spec spec:unit spec:integration].each do |name|
|
25
|
-
task name do
|
26
|
-
$stderr.puts "In order to run #{name}, do `gem install rspec`"
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
data/tty-editor.gemspec
DELETED
@@ -1,30 +0,0 @@
|
|
1
|
-
# coding: utf-8
|
2
|
-
lib = File.expand_path('../lib', __FILE__)
|
3
|
-
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require 'tty/editor/version'
|
5
|
-
|
6
|
-
Gem::Specification.new do |spec|
|
7
|
-
spec.name = "tty-editor"
|
8
|
-
spec.version = TTY::Editor::VERSION
|
9
|
-
spec.authors = ["Piotr Murach"]
|
10
|
-
spec.email = [""]
|
11
|
-
|
12
|
-
spec.summary = %q{Opens a file or text in the user's preferred editor.}
|
13
|
-
spec.description = %q{Opens a file or text in the user's preferred editor.}
|
14
|
-
spec.homepage = "https://piotrmurach.github.io/tty"
|
15
|
-
spec.license = "MIT"
|
16
|
-
|
17
|
-
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
18
|
-
spec.bindir = "exe"
|
19
|
-
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
|
-
spec.require_paths = ["lib"]
|
21
|
-
|
22
|
-
spec.required_ruby_version = '>= 2.0.0'
|
23
|
-
|
24
|
-
spec.add_dependency 'tty-prompt', '~> 0.14.0'
|
25
|
-
spec.add_dependency 'tty-which', '~> 0.3.0'
|
26
|
-
|
27
|
-
spec.add_development_dependency 'bundler', '>= 1.5.0', '< 2.0'
|
28
|
-
spec.add_development_dependency 'rake', '~> 10.0'
|
29
|
-
spec.add_development_dependency 'rspec', '~> 3.0'
|
30
|
-
end
|