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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 0b9918234c5fc0e4eabd6a59d859fc16a2827c88
4
- data.tar.gz: e609ed53f8aa25a9590405d924ac27a35f8fb47c
2
+ SHA256:
3
+ metadata.gz: 43382f86c223e305662a67b003a4337ce5946adaee09dcd48879714a91e45eae
4
+ data.tar.gz: fd58b6084c4cbedd605c09ce30fca817ea7f4d467e32ddfd558e3c7eb972f0a4
5
5
  SHA512:
6
- metadata.gz: bea5f34a6cd157e0804107ffa1c6fec9ade2a12bebe6506843a56f212bb2a93af37050ed5e5ed7bd359e3a1e76bd8a0a11efc3b9e8261f37093bf962e852df27
7
- data.tar.gz: 21dd8869bcba744dc42759e70f70db5e653e597eee5b13b1cb258f55e5b8965502ca2a37d5a7582d9d6fae318c6c2d8213232a54bcfe53cc62b7a2ccf8671f71
6
+ metadata.gz: 31385f2ece1195d0c3801e495830c182f6808050c510ae83f3c78f48117a6a6a088ffce3177ea5283507a7e67cc235f6e580261e73ce03d0916044eeaeed0209
7
+ data.tar.gz: ddf5f4e74879e30a641ca4d3c7af06ffb0b7e36f8dd989915d599b283855e1fee77843d4788dd60eb7be93b1ef47b77285abb4a06b60528a36aefae75717dead
@@ -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](https://badges.gitter.im/Join%20Chat.svg)][gitter]
2
6
 
3
7
  [![Gem Version](https://badge.fury.io/rb/tty-editor.svg)][gem]
@@ -24,7 +28,7 @@
24
28
  Add this line to your application's Gemfile:
25
29
 
26
30
  ```ruby
27
- gem 'tty-editor'
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
- ## Usage
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 a file in default editor:
61
+ To edit text in a default editor:
41
62
 
42
63
  ```ruby
43
- TTY::Editor.open('hello.rb')
64
+ TTY::Editor.open(text: "Some text")
44
65
  ```
45
66
 
46
- To edit content in a default editor:
67
+ You can also open multiple existing and/or new files:
47
68
 
48
69
  ```ruby
49
- TTY::Editor.open(content: "some text")
70
+ TTY::Editor.open("file_1", "file_2", "new_file_3")
50
71
  ```
51
72
 
52
- You can also set your preferred editor command:
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('hello.rb', command: :vim)
78
+ TTY::Editor.open("/path/to/file", command: "vim -f")
56
79
  ```
57
80
 
58
- Also, the `VISUAL` or `EDITOR` shell environment variables take precedencee when auto detecting available editors.
81
+ When `VISUAL` or `EDITOR` are not specified, a selection menu will be presented to the user.
59
82
 
60
- ## Interface
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
- ### open
85
+ ```
86
+ # Select an editor?
87
+ # 1) vim
88
+ # 2) emacs
89
+ # 3) code
90
+ # Choose 1-2 [1]:
91
+ ```
63
92
 
64
- If you wish to open editor with no file or content do:
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.open
102
+ editor = TTY::Editor.new
68
103
  ```
69
104
 
70
- When editor successfully opens file or content then `true` is returned.
105
+ You can change default search with the `:command` keyword argument.
71
106
 
72
- If the editor cannot be opened, a `TTY::Editor::CommandInvocation` error is raised.
107
+ #### 2.1.1 :command
73
108
 
74
- In order to open text content inside an editor do:
109
+ You can force to always use a specific editor by passing `:command` option:
75
110
 
76
111
  ```ruby
77
- TTY::Editor.open(content: 'text')
112
+ editor = TTY::Editor.new(command: "vim")
78
113
  ```
79
114
 
80
- You can also provide filename that will be created with specified content before editor is opened:
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('new.rb', content: 'text')
124
+ TTY::Editor.open("/path/to/file", command: "vim")
84
125
  ```
85
126
 
86
- If you open a filename with already existing content then new content gets appended at the end of the file.
127
+ #### 2.1.2 :env
87
128
 
88
- ### :env
129
+ Use `:env` key to forward environment variables to the text editor launch command:
89
130
 
90
- Use `:env` key to forward environment variables to the editor.
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('hello.rb', env: {"FOO" => "bar"})
138
+ TTY::Editor.open("/path/to/file", env: {"FOO" => "bar"})
94
139
  ```
95
140
 
96
- ### :command
141
+ #### 2.1.3 :raise_on_failure
97
142
 
98
- You can force to always use a specific editor by passing `:command` option:
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('hello.rb', command: :vim)
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-2018 Piotr Murach. See LICENSE for further details.
260
+ Copyright (c) 2017 Piotr Murach. See LICENSE for further details.
@@ -1,3 +1 @@
1
- # encoding: utf-8
2
-
3
- require_relative 'tty/editor'
1
+ require_relative "tty/editor"
@@ -1,40 +1,53 @@
1
- # encoding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
- require 'tty-prompt'
4
- require 'tty-which'
5
- require 'tempfile'
6
- require 'fileutils'
7
- require 'shellwords'
3
+ require "fileutils"
4
+ require "shellwords"
5
+ require "tempfile"
6
+ require "tty-prompt"
8
7
 
9
- require_relative 'editor/version'
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
- # Check if editor exists
26
+ # List possible command line text editors
23
27
  #
24
- # @return [Boolean]
28
+ # @return [Array[String]]
25
29
  #
26
- # @api private
27
- def self.exist?(cmd)
28
- TTY::Which.exist?(cmd)
29
- end
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 Windowz
37
+ # Check if editor command exists
38
+ #
39
+ # @example
40
+ # exist?("vim") # => true
32
41
  #
33
42
  # @return [Boolean]
34
43
  #
35
- # @api public
36
- def self.windows?
37
- ::File::ALT_SEPARATOR == "\\"
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['VISUAL'], ENV['EDITOR']].compact
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 command
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
- return commands unless commands.empty?
68
-
69
- if !from_env.all?(&:empty?)
70
- [from_env.find { |e| !e.empty? }]
71
- elsif windows?
72
- ['notepad']
73
- else
74
- executables.uniq.select(&method(:exist?))
75
- end
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('filename.rb')
86
+ # TTY::Editor.open("/path/to/filename")
82
87
  #
83
- # @param [String] file
84
- # the name of the file
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(*args)
90
- editor = new(*args)
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] file
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
- # @option options [Hash] :env
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(*args, **options)
108
- @filename = args.unshift.first
109
- @env = options.fetch(:env) { {} }
110
- @command = options[:command]
111
- if @filename
112
- if ::File.exist?(@filename) && !::FileTest.file?(@filename)
113
- raise ArgumentError, "Don't know how to handle `#{@filename}`. " \
114
- "Please provida a file path or content"
115
- elsif ::File.exist?(@filename) && !options[:content].to_s.empty?
116
- ::File.open(@filename, 'a') { |f| f.write(options[:content]) }
117
- elsif !::File.exist?(@filename)
118
- ::File.write(@filename, options[:content])
119
- end
120
- elsif options[:content]
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
- 'Could not find editor to use. Please specify $VISUAL or $EDITOR'
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
- exec = choose_exec_from(execs)
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 choose_exec_from(execs)
157
- if execs.size > 1
158
- prompt = TTY::Prompt.new
159
- prompt.enum_select('Select an editor?', execs)
160
- else
161
- execs[0]
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
- # Escape file path
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 escape_file
169
- Shellwords.shellescape(@filename)
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
- # Build command path to invoke
233
+ # Check if filename and text arguments are valid
173
234
  #
174
- # @return [String]
235
+ # @raise [InvalidArgumentError]
175
236
  #
176
237
  # @api private
177
- def command_path
178
- "#{command} #{escape_file}"
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 content
250
+ # Create tempfile with text
182
251
  #
183
- # @param [String] content
252
+ # @param [String] text
253
+ #
254
+ # @return [Tempfile]
184
255
  #
185
- # @return [String]
186
256
  # @api private
187
- def tempfile_path(content)
188
- tempfile = Tempfile.new('tty-editor')
189
- tempfile << content
257
+ def create_tempfile(text)
258
+ tempfile = Tempfile.new("tty-editor")
259
+ tempfile << text
190
260
  tempfile.flush
191
- unless tempfile.nil?
192
- tempfile.close
193
- end
194
- tempfile.path
261
+ tempfile.close
262
+ tempfile
195
263
  end
196
264
 
197
- # Inovke editor command in a shell
265
+ # Render an editor selection prompt to the terminal
198
266
  #
199
- # @raise [TTY::CommandInvocationError]
267
+ # @return [String]
268
+ # the chosen editor
200
269
  #
201
270
  # @api private
202
- def open
203
- status = system(env, *Shellwords.split(command_path))
204
- return status if status
205
- fail CommandInvocationError,
206
- "`#{command_path}` failed with status: #{$? ? $?.exitstatus : nil}"
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
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module TTY
2
4
  class Editor
3
- VERSION = '0.3.0'.freeze
5
+ VERSION = "0.6.0"
4
6
  end # Editor
5
7
  end # TTY
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.3.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Piotr Murach
8
8
  autorequire:
9
- bindir: exe
9
+ bindir: bin
10
10
  cert_chain: []
11
- date: 2018-01-06 00:00:00.000000000 Z
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.14.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.14.0
26
+ version: '0.22'
27
27
  - !ruby/object:Gem::Dependency
28
- name: tty-which
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: 1.5.0
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: 1.5.0
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: Opens a file or text in the user's preferred editor.
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
- - tasks/console.rake
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
- rubyforge_project:
140
- rubygems_version: 2.5.1
96
+ rubygems_version: 3.1.2
141
97
  signing_key:
142
98
  specification_version: 4
143
- summary: Opens a file or text in the user's preferred editor.
99
+ summary: Open a file or text in a terminal text editor.
144
100
  test_files: []
data/.gitignore DELETED
@@ -1,9 +0,0 @@
1
- /.bundle/
2
- /.yardoc
3
- /Gemfile.lock
4
- /_yardoc/
5
- /coverage/
6
- /doc/
7
- /pkg/
8
- /spec/reports/
9
- /tmp/
data/.rspec DELETED
@@ -1,3 +0,0 @@
1
- --require spec_helper
2
- --color
3
- --warnings
@@ -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
@@ -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
@@ -1,8 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- gemspec
4
-
5
- group :test do
6
- gem 'simplecov', '~> 0.12.0'
7
- gem 'coveralls', '~> 0.8.0'
8
- end
data/Rakefile DELETED
@@ -1,10 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require "bundler/gem_tasks"
4
-
5
- FileList['tasks/**/*.rake'].each(&method(:import))
6
-
7
- task default: :spec
8
-
9
- desc 'Run all specs'
10
- task ci: %w[ spec ]
@@ -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"
@@ -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
@@ -1,8 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
- IFS=$'\n\t'
4
- set -vx
5
-
6
- bundle install
7
-
8
- # Do any other automated setup that you need to do here
@@ -1,7 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'tty-editor'
4
-
5
- path = File.join(File.expand_path(File.dirname(__FILE__)), '../README.md')
6
-
7
- TTY::Editor.open(path)
@@ -1,9 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'tty-editor'
4
-
5
- path = File.join(File.expand_path(File.dirname(__FILE__)), '../README.md')
6
-
7
- TTY::Editor.open(path) do |editor|
8
- editor.command :vim, :emacs
9
- end
@@ -1,5 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'tty-editor'
4
-
5
- TTY::Editor.open
@@ -1,7 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'tty-editor'
4
-
5
- path = File.join(File.expand_path(File.dirname(__FILE__)), '../README.md')
6
-
7
- TTY::Editor.open(path, env: {"FOO" => "bar"})
@@ -1,7 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'tty-editor'
4
-
5
- content = "Human madness is oftentimes a cunning and most feline thing.\n When you think it fled, it may have but become transfigured into some still subtler form."
6
-
7
- TTY::Editor.open(content)
@@ -1,10 +0,0 @@
1
- # encoding: utf-8
2
-
3
- desc 'Load gem inside irb console'
4
- task :console do
5
- require 'irb'
6
- require 'irb/completion'
7
- require File.join(__FILE__, '../../lib/tty-editor')
8
- ARGV.clear
9
- IRB.start
10
- end
@@ -1,11 +0,0 @@
1
- # encoding: utf-8
2
-
3
- desc 'Measure code coverage'
4
- task :coverage do
5
- begin
6
- original, ENV['COVERAGE'] = ENV['COVERAGE'], 'true'
7
- Rake::Task['spec'].invoke
8
- ensure
9
- ENV['COVERAGE'] = original
10
- end
11
- end
@@ -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
@@ -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