rbnotes 0.3.1 → 0.4.4
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 +4 -4
- data/CHANGELOG.md +27 -0
- data/Gemfile +1 -1
- data/Gemfile.lock +4 -4
- data/README.md +37 -0
- data/exe/rbnotes +10 -3
- data/lib/rbnotes.rb +2 -0
- data/lib/rbnotes/commands.rb +158 -39
- data/lib/rbnotes/commands/add.rb +92 -9
- data/lib/rbnotes/commands/delete.rb +24 -12
- data/lib/rbnotes/commands/export.rb +58 -0
- data/lib/rbnotes/commands/help.rb +98 -0
- data/lib/rbnotes/commands/import.rb +39 -2
- data/lib/rbnotes/commands/list.rb +83 -7
- data/lib/rbnotes/commands/search.rb +67 -0
- data/lib/rbnotes/commands/show.rb +33 -2
- data/lib/rbnotes/commands/update.rb +57 -18
- data/lib/rbnotes/utils.rb +5 -1
- data/lib/rbnotes/version.rb +2 -2
- data/rbnotes.gemspec +1 -1
- metadata +7 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a04bd4d45d7c2f4227f355672baa860602ae3b9e481e7a384daf4283f4ad6754
|
4
|
+
data.tar.gz: bc707b20ea91ab655f6e355026164c01844c82ea3869c18fd5ca1040c968934d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d93df0df9e002a8bae26b7d9e1e89acf19d84551635d58f3ec747c78f3764ac004a784977a3d9940783a8b4661b2caafd2b55502644bca4bb69947d91593bd79
|
7
|
+
data.tar.gz: 913c240b04215cb5502146f4d1edcd5c1ddc273de31baace3f0d8dff600dcf759e5983aee5cce72fb5079dc26e1a22b43c0aad46e1cc766c4127697090fb0037
|
data/CHANGELOG.md
CHANGED
@@ -7,6 +7,33 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
7
7
|
## [Unreleased]
|
8
8
|
Nothing to record here.
|
9
9
|
|
10
|
+
## [0.4.4] - 2020-11-09
|
11
|
+
###
|
12
|
+
- Add a feature to use a keyword as an argument for `list`. (#47)
|
13
|
+
|
14
|
+
## [0.4.3] - 2020-11-08
|
15
|
+
### Added
|
16
|
+
- Add a new command `export` to write out a note into a file. (#51)
|
17
|
+
- Add individual help for each command. (#42)
|
18
|
+
|
19
|
+
### Fixed
|
20
|
+
- Fix `add` fails without modification (#48)
|
21
|
+
|
22
|
+
## [0.4.2] - 2020-11-05
|
23
|
+
### Added
|
24
|
+
- Add a feature to keep the timestamp in `update` command. (#44)
|
25
|
+
|
26
|
+
### Fixed
|
27
|
+
- Fix issue #45: hanging up of `add` command.
|
28
|
+
|
29
|
+
## [0.4.1] - 2020-11-04
|
30
|
+
### Added
|
31
|
+
- Add a feature to accept a timestamp in `add` command. (#34)
|
32
|
+
|
33
|
+
## [0.4.0] - 2020-11-03
|
34
|
+
### Added
|
35
|
+
- Add a new command `search` to perform full text search. (#33)
|
36
|
+
|
10
37
|
## [0.3.1] - 2020-10-30
|
11
38
|
### Added
|
12
39
|
- Add feature to specify configuration file in the command line. (#21)
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
rbnotes (0.
|
5
|
-
textrepo (~> 0.4)
|
4
|
+
rbnotes (0.4.4)
|
5
|
+
textrepo (~> 0.5.4)
|
6
6
|
unicode-display_width (~> 1.7)
|
7
7
|
|
8
8
|
GEM
|
@@ -10,7 +10,7 @@ GEM
|
|
10
10
|
specs:
|
11
11
|
minitest (5.14.2)
|
12
12
|
rake (13.0.1)
|
13
|
-
textrepo (0.4
|
13
|
+
textrepo (0.5.4)
|
14
14
|
unicode-display_width (1.7.0)
|
15
15
|
|
16
16
|
PLATFORMS
|
@@ -20,7 +20,7 @@ DEPENDENCIES
|
|
20
20
|
minitest (~> 5.0)
|
21
21
|
rake (~> 13.0)
|
22
22
|
rbnotes!
|
23
|
-
textrepo (~> 0.4)
|
23
|
+
textrepo (~> 0.5.4)
|
24
24
|
|
25
25
|
BUNDLED WITH
|
26
26
|
2.1.4
|
data/README.md
CHANGED
@@ -4,6 +4,9 @@
|
|
4
4
|
|
5
5
|
Rbnotes is a simple utility to write a note in the single repository.
|
6
6
|
|
7
|
+
This document provides the basic information to use rbnotes.
|
8
|
+
You may find more useful information in [Wiki pages](https://github.com/mnbi/rbnotes/wiki).
|
9
|
+
|
7
10
|
## Installation
|
8
11
|
|
9
12
|
Add this line to your application's Gemfile:
|
@@ -39,6 +42,8 @@ rbnotes [global_opts] [command] [command_opts] [args]
|
|
39
42
|
- imports existing files
|
40
43
|
- list
|
41
44
|
- lists notes in the repository with their timestamps and subject
|
45
|
+
- search
|
46
|
+
- search a word (or words) in the repository
|
42
47
|
- show
|
43
48
|
- shows the content of a note
|
44
49
|
- add
|
@@ -145,6 +150,38 @@ The short-hand notation of the home directory ("~") is usable.
|
|
145
150
|
|
146
151
|
- :pager : specify a pager program
|
147
152
|
- :editor : specify a editor program
|
153
|
+
- :searcher: specify a program to perform search
|
154
|
+
- :searcher_options: specify options to pass to the searcher program
|
155
|
+
|
156
|
+
Be careful to set `:searcher` and `:searcher_options`. The searcher
|
157
|
+
program must be expected to behave equivalent to `grep` with `-inRE`.
|
158
|
+
At least, its output must be the same format and it must runs
|
159
|
+
recursively to a directory.
|
160
|
+
|
161
|
+
If your favorite searcher is one of the followings, see the default
|
162
|
+
options which `textrepo` sets for those searchers. In most cases, you
|
163
|
+
don't have to set `:searcher_options` for them.
|
164
|
+
|
165
|
+
| searcher | default options in `textrepo` |
|
166
|
+
|:---------|:---------------------------------------------------|
|
167
|
+
| `grep` | `["-i", "-n", "-R", "-E"]` |
|
168
|
+
| `egrep` | `["-i", "-n", "-R"]` |
|
169
|
+
| `ggrep` | `["-i", "-n", "-R", "-E"]` |
|
170
|
+
| `gegrep` | `["-i", "-n", "-R"]` |
|
171
|
+
| `rg` | `["-S", "-n", "--no-heading", "--color", "never"]` |
|
172
|
+
|
173
|
+
Those searcher names are used in macOS (with Homebrew). Any other OS
|
174
|
+
might use different names.
|
175
|
+
|
176
|
+
- `grep` and `egrep` -> BSD grep (macOS default)
|
177
|
+
- `ggrep` and `gegrep` -> GNU grep
|
178
|
+
- `rg` -> ripgrep
|
179
|
+
|
180
|
+
If the name is different, `:searcher_options` should be set with the
|
181
|
+
same value. For example, if you system use the name `gnugrep` as GNU
|
182
|
+
grep, and you want to use it as the searcher (that is, set `gnugrep`
|
183
|
+
to `:searcher`), you should set `:searcher_options` value with `["-i",
|
184
|
+
"-n", "-R", "-E"]`.
|
148
185
|
|
149
186
|
##### Default values for mandatory variables
|
150
187
|
|
data/exe/rbnotes
CHANGED
@@ -4,8 +4,6 @@ require "rbnotes"
|
|
4
4
|
|
5
5
|
include Rbnotes
|
6
6
|
|
7
|
-
DEBUG = true
|
8
|
-
|
9
7
|
class App
|
10
8
|
def initialize
|
11
9
|
@gopts = {}
|
@@ -25,6 +23,14 @@ class App
|
|
25
23
|
file = File.expand_path(file)
|
26
24
|
raise ArgumentError, "no such file: %s" % file unless FileTest.exist?(file)
|
27
25
|
@gopts[:conf_file] = file
|
26
|
+
when "-v", "--version"
|
27
|
+
args.clear
|
28
|
+
args.unshift("version")
|
29
|
+
break
|
30
|
+
when "-h", "--help"
|
31
|
+
args.clear
|
32
|
+
args.unshift("help")
|
33
|
+
break
|
28
34
|
else
|
29
35
|
args.unshift(arg)
|
30
36
|
break
|
@@ -45,7 +51,8 @@ begin
|
|
45
51
|
rescue MissingArgumentError, MissingTimestampError,
|
46
52
|
NoEditorError, ProgramAbortError,
|
47
53
|
Textrepo::InvalidTimestampStringError,
|
48
|
-
ArgumentError
|
54
|
+
ArgumentError,
|
55
|
+
Errno::EACCES => e
|
49
56
|
puts e.message
|
50
57
|
exit 1
|
51
58
|
end
|
data/lib/rbnotes.rb
CHANGED
data/lib/rbnotes/commands.rb
CHANGED
@@ -1,14 +1,21 @@
|
|
1
1
|
module Rbnotes
|
2
|
+
|
2
3
|
##
|
3
4
|
# This module defines all command classes of rbnotes. Each command
|
4
5
|
# class must be derived from Rbnotes::Commands::Command class.
|
5
6
|
|
6
7
|
module Commands
|
8
|
+
|
7
9
|
##
|
8
10
|
# The base class for a command class.
|
9
11
|
|
10
12
|
class Command
|
11
13
|
|
14
|
+
##
|
15
|
+
# Short description of each command.
|
16
|
+
|
17
|
+
def description; nil; end
|
18
|
+
|
12
19
|
##
|
13
20
|
# :call-seq:
|
14
21
|
# execute(Array, Hash) -> nil
|
@@ -17,8 +24,17 @@ module Rbnotes
|
|
17
24
|
# - Hash : rbnotes configuration
|
18
25
|
|
19
26
|
def execute(args, conf)
|
20
|
-
Builtins
|
27
|
+
Builtins.default_cmd.new.execute(args, conf)
|
28
|
+
end
|
29
|
+
|
30
|
+
##
|
31
|
+
# Shows the help message for the command.
|
32
|
+
#
|
33
|
+
|
34
|
+
def help
|
35
|
+
Builtins::Usage.new.execute(nil, nil)
|
21
36
|
end
|
37
|
+
|
22
38
|
end
|
23
39
|
|
24
40
|
# :stopdoc:
|
@@ -29,54 +45,73 @@ module Rbnotes
|
|
29
45
|
# - stamp: converts given TIME_STR into a timestamp.
|
30
46
|
# - time: converts given STAMP into a time string.
|
31
47
|
module Builtins
|
32
|
-
class
|
33
|
-
def execute(_, _)
|
34
|
-
puts <<USAGE
|
35
|
-
usage: rbnotes [-c|--conf CONF_FILE] [command] [args]
|
48
|
+
class Usage < Command
|
36
49
|
|
37
|
-
|
38
|
-
|
39
|
-
|
50
|
+
def description
|
51
|
+
"Print usage"
|
52
|
+
end
|
40
53
|
|
41
|
-
|
54
|
+
def execute(_, _)
|
55
|
+
puts <<USAGE
|
56
|
+
Syntax:
|
57
|
+
#{Rbnotes::NAME} [-c| --conf CONF_FILE] [command] [args]
|
42
58
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
59
|
+
Example usage:
|
60
|
+
#{Rbnotes::NAME} add [-t STAMP_PATTERN]
|
61
|
+
#{Rbnotes::NAME} delete [TIMESTAMP]
|
62
|
+
#{Rbnotes::NAME} export [TIMESTAMP [FILENAME]]
|
63
|
+
#{Rbnotes::NAME} import FILE
|
64
|
+
#{Rbnotes::NAME} list [STAMP_PATTERN|KEYWORD]
|
65
|
+
#{Rbnotes::NAME} search PATTERN [STAMP_PATTERN]
|
66
|
+
#{Rbnotes::NAME} show [TIMESTAMP]
|
67
|
+
#{Rbnotes::NAME} update [TIMESTAMP]
|
48
68
|
|
49
|
-
|
50
|
-
|
51
|
-
|
69
|
+
Further help for each command:
|
70
|
+
#{Rbnotes::NAME} help commands
|
71
|
+
#{Rbnotes::NAME} help [COMMAND]
|
52
72
|
|
53
|
-
|
54
|
-
|
73
|
+
Further information:
|
74
|
+
https://github.com/mnbi/rbnotes/wiki
|
55
75
|
|
56
|
-
|
57
|
-
|
76
|
+
USAGE
|
77
|
+
end
|
58
78
|
|
59
|
-
|
60
|
-
|
79
|
+
def help
|
80
|
+
puts <<HELP_USAGE
|
81
|
+
usage:
|
82
|
+
#{Rbnotes::NAME} usage
|
61
83
|
|
62
|
-
|
63
|
-
|
64
|
-
repo : print the repository path
|
65
|
-
stamp TIME_STR : convert TIME_STR into a timestamp
|
66
|
-
time STAMP : convert STAMP into a time string
|
67
|
-
USAGE
|
84
|
+
Print a short example of usage.
|
85
|
+
HELP_USAGE
|
68
86
|
end
|
69
87
|
end
|
70
88
|
|
71
89
|
class Version < Command
|
90
|
+
def description
|
91
|
+
"Print version"
|
92
|
+
end
|
93
|
+
|
72
94
|
def execute(_, _)
|
73
|
-
rbnotes_version = "
|
95
|
+
rbnotes_version = "#{Rbnotes::NAME} #{Rbnotes::VERSION} (#{Rbnotes::RELEASE})"
|
74
96
|
textrepo_version = "textrepo #{Textrepo::VERSION}"
|
75
97
|
puts "#{rbnotes_version} [#{textrepo_version}]"
|
76
98
|
end
|
99
|
+
|
100
|
+
def help
|
101
|
+
puts <<VERSION
|
102
|
+
usage:
|
103
|
+
#{Rbnotes::NAME} version
|
104
|
+
|
105
|
+
Print version of #{Rbnotes::NAME} and release date.
|
106
|
+
VERSION
|
107
|
+
end
|
77
108
|
end
|
78
109
|
|
79
110
|
class Repo < Command
|
111
|
+
def description
|
112
|
+
"Print repository path"
|
113
|
+
end
|
114
|
+
|
80
115
|
def execute(_, conf)
|
81
116
|
name = conf[:repository_name]
|
82
117
|
base = conf[:repository_base]
|
@@ -89,19 +124,49 @@ USAGE
|
|
89
124
|
File.join(base, name)
|
90
125
|
end
|
91
126
|
end
|
127
|
+
|
128
|
+
def help
|
129
|
+
puts <<REPO
|
130
|
+
usage:
|
131
|
+
#{Rbnotes::NAME} repo
|
132
|
+
|
133
|
+
Print the path of the repository. The type of the path entity depends
|
134
|
+
on what type is specified to the repository type in the configuration.
|
135
|
+
When ":file_system" is set to "repository_type", the path is a
|
136
|
+
directory which contains all note files. The structure of the
|
137
|
+
directory depends on the implementation of `textrepo`.
|
138
|
+
REPO
|
139
|
+
end
|
92
140
|
end
|
93
141
|
|
94
142
|
class Conf < Command
|
143
|
+
def description
|
144
|
+
"Print the current configuration"
|
145
|
+
end
|
146
|
+
|
95
147
|
def execute(_, conf)
|
96
148
|
conf.keys.sort.each { |k|
|
97
149
|
puts "#{k}=#{conf[k]}"
|
98
150
|
}
|
99
151
|
end
|
152
|
+
|
153
|
+
def help
|
154
|
+
puts <<CONF
|
155
|
+
usage:
|
156
|
+
#{Rbnotes::NAME} conf
|
157
|
+
|
158
|
+
Print the current configuration values.
|
159
|
+
CONF
|
160
|
+
end
|
100
161
|
end
|
101
162
|
|
102
163
|
require "time"
|
103
164
|
|
104
165
|
class Stamp < Command
|
166
|
+
def description
|
167
|
+
"Convert a time string into a timestamp string"
|
168
|
+
end
|
169
|
+
|
105
170
|
def execute(args, _)
|
106
171
|
time_str = args.shift
|
107
172
|
unless time_str.nil?
|
@@ -111,9 +176,30 @@ USAGE
|
|
111
176
|
super
|
112
177
|
end
|
113
178
|
end
|
179
|
+
|
180
|
+
def help
|
181
|
+
puts <<STAMP
|
182
|
+
usage:
|
183
|
+
#{Rbnotes::NAME} stamp
|
184
|
+
|
185
|
+
Convert a given time string into a timestamp string. The timestamp
|
186
|
+
string could be used as an argument of some rbnotes commands, such
|
187
|
+
"show". Here is short example of conversion:
|
188
|
+
|
189
|
+
"2020-11-06 16:51:15" -> "20201106165115"
|
190
|
+
"2020-11-06" -> "20201106000000"
|
191
|
+
"20201106" -> "20201106000000"
|
192
|
+
"2020-11-06 16" -> "20201106160000"
|
193
|
+
"2020-11-06 16:51" -> "20201106165100"
|
194
|
+
STAMP
|
195
|
+
end
|
114
196
|
end
|
115
197
|
|
116
198
|
class Time < Command
|
199
|
+
def description
|
200
|
+
"Convert a timestamp into a time string"
|
201
|
+
end
|
202
|
+
|
117
203
|
def execute(args, _)
|
118
204
|
stamp = args.shift
|
119
205
|
unless stamp.nil?
|
@@ -123,12 +209,41 @@ USAGE
|
|
123
209
|
super
|
124
210
|
end
|
125
211
|
end
|
212
|
+
|
213
|
+
def help
|
214
|
+
puts <<TIME
|
215
|
+
usage:
|
216
|
+
#{Rbnotes::NAME} time
|
217
|
+
|
218
|
+
Convert a given timestamp string into a time string. Here is short
|
219
|
+
example of conversion:
|
220
|
+
|
221
|
+
"20201106165115" -> "2020-11-06 16:51:15 +0900"
|
222
|
+
"202011061651" -> "2020-11-06 16:51:00 +0900"
|
223
|
+
"2020110616" -> "2020-11-06 16:00:00 +0900"
|
224
|
+
"20201106" -> "2020-11-06 00:00:00 +0900"
|
225
|
+
TIME
|
226
|
+
end
|
126
227
|
end
|
127
228
|
|
128
|
-
|
129
|
-
|
229
|
+
class << self
|
230
|
+
def default_cmd_name
|
231
|
+
"usage"
|
232
|
+
end
|
130
233
|
|
131
|
-
|
234
|
+
def default_cmd
|
235
|
+
Usage
|
236
|
+
end
|
237
|
+
|
238
|
+
def command(name)
|
239
|
+
begin
|
240
|
+
const_defined?(name, false) ? const_get(name, false) : nil
|
241
|
+
rescue NameError => _
|
242
|
+
nil
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|
132
247
|
|
133
248
|
# :startdoc:
|
134
249
|
|
@@ -139,24 +254,28 @@ USAGE
|
|
139
254
|
# of the class.
|
140
255
|
#
|
141
256
|
# :call-seq:
|
257
|
+
# load("add") -> Rbnotes::Commands::Add
|
258
|
+
# load("delete") -> Rbnotes::Commands::Delete
|
259
|
+
# load("export") -> Rbnotes::Commands::Export
|
260
|
+
# load("help") -> Rbnotes::Commands::Help
|
142
261
|
# load("import") -> Rbnotes::Commnads::Import
|
143
262
|
# load("list") -> Rbnotes::Commands::List
|
263
|
+
# load("search") -> Rbnotes::Commands::Search
|
144
264
|
# load("show") -> Rbnotes::Commands::Show
|
265
|
+
# load("update") -> Rbnotes::Commands::Update
|
145
266
|
|
146
267
|
def load(cmd_name)
|
147
|
-
cmd_name ||=
|
268
|
+
cmd_name ||= Builtins.default_cmd_name
|
148
269
|
klass_name = cmd_name.capitalize
|
149
270
|
|
150
|
-
klass =
|
151
|
-
if
|
152
|
-
klass = Builtins::const_get(klass_name, false)
|
153
|
-
else
|
271
|
+
klass = Builtins.command(klass_name)
|
272
|
+
if klass.nil?
|
154
273
|
begin
|
155
274
|
require_relative "commands/#{cmd_name}"
|
156
275
|
klass = const_get(klass_name, false)
|
157
276
|
rescue LoadError => _
|
158
277
|
STDERR.puts "unknown command: #{cmd_name}"
|
159
|
-
klass = Builtins
|
278
|
+
klass = Builtins.default_cmd
|
160
279
|
end
|
161
280
|
end
|
162
281
|
klass.new
|
data/lib/rbnotes/commands/add.rb
CHANGED
@@ -1,9 +1,20 @@
|
|
1
1
|
module Rbnotes::Commands
|
2
|
+
|
2
3
|
##
|
3
|
-
# Adds a new note to the repository.
|
4
|
-
# at the execution time, then it is attached to the
|
5
|
-
# timestamp has already existed in the repository, the
|
6
|
-
# fails.
|
4
|
+
# Adds a new note to the repository. If no options, a new timestamp
|
5
|
+
# is generated at the execution time, then it is attached to the
|
6
|
+
# note. If the timestamp has already existed in the repository, the
|
7
|
+
# command fails.
|
8
|
+
#
|
9
|
+
# Accepts an option with `-t STAMP_PATTERN` (or `--timestamp`), a
|
10
|
+
# timestamp is generated according to `STAMP_PATTERN`.
|
11
|
+
#
|
12
|
+
# STAMP_PATTERN could be one of followings:
|
13
|
+
#
|
14
|
+
# "20201104172230_078" : full qualified timestamp string
|
15
|
+
# "20201104172230" : full qualified timestamp string (no suffix)
|
16
|
+
# "202011041722" : year, date and time (omit second part)
|
17
|
+
# "11041722" : date and time (omit year and second part)
|
7
18
|
#
|
8
19
|
# This command starts the external editor program to prepare text to
|
9
20
|
# store. The editor program will be searched in the following order:
|
@@ -14,23 +25,48 @@ module Rbnotes::Commands
|
|
14
25
|
# 4. "vi"
|
15
26
|
#
|
16
27
|
# If none of the above editor is available, the command fails.
|
17
|
-
|
28
|
+
|
18
29
|
class Add < Command
|
19
30
|
include ::Rbnotes::Utils
|
20
31
|
|
32
|
+
def description # :nodoc:
|
33
|
+
"Add a new note"
|
34
|
+
end
|
35
|
+
|
21
36
|
def execute(args, conf)
|
22
|
-
|
37
|
+
@opts = {}
|
38
|
+
while args.size > 0
|
39
|
+
arg = args.shift
|
40
|
+
case arg
|
41
|
+
when "-t", "--timestamp"
|
42
|
+
stamp_str = args.shift
|
43
|
+
raise ArgumentError, "missing timestamp: %s" % args.unshift(arg) if stamp_str.nil?
|
44
|
+
stamp_str = complement_timestamp_pattern(stamp_str)
|
45
|
+
@opts[:timestamp] = Textrepo::Timestamp.parse_s(stamp_str)
|
46
|
+
else
|
47
|
+
args.unshift(arg)
|
48
|
+
break
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
stamp = @opts[:timestamp] || Textrepo::Timestamp.new(Time.now)
|
23
53
|
|
24
54
|
candidates = [conf[:editor], ENV["EDITOR"], "nano", "vi"].compact
|
25
55
|
editor = find_program(candidates)
|
26
56
|
raise Rbnotes::NoEditorError, candidates if editor.nil?
|
27
57
|
|
28
|
-
tmpfile = run_with_tmpfile(editor,
|
58
|
+
tmpfile = run_with_tmpfile(editor, stamp.to_s)
|
59
|
+
|
60
|
+
unless FileTest.exist?(tmpfile)
|
61
|
+
puts "Cancel adding, since nothing to store"
|
62
|
+
return
|
63
|
+
end
|
64
|
+
|
29
65
|
text = File.readlines(tmpfile)
|
30
66
|
|
31
67
|
repo = Textrepo.init(conf)
|
32
68
|
begin
|
33
|
-
repo.create(
|
69
|
+
repo.create(stamp, text)
|
34
70
|
rescue Textrepo::DuplicateTimestampError => e
|
35
71
|
puts e.message
|
36
72
|
puts "Just wait a second, then retry."
|
@@ -39,11 +75,58 @@ module Rbnotes::Commands
|
|
39
75
|
rescue StandardError => e
|
40
76
|
puts e.message
|
41
77
|
else
|
42
|
-
puts "Add a note [%s]" %
|
78
|
+
puts "Add a note [%s]" % stamp.to_s
|
43
79
|
ensure
|
44
80
|
# Don't forget to remove the temporary file.
|
45
81
|
File.delete(tmpfile)
|
46
82
|
end
|
47
83
|
end
|
84
|
+
|
85
|
+
def help # :nodoc:
|
86
|
+
puts <<HELP
|
87
|
+
usage:
|
88
|
+
#{Rbnotes::NAME} add [(-t|--timestamp) STAMP_PATTERN]
|
89
|
+
|
90
|
+
Add a new note to the repository. If no options, a new timestamp is
|
91
|
+
generated at the execution time, then it is attached to the note.
|
92
|
+
|
93
|
+
Accept an option with `-t STAMP_PATTERN` (or `--timestamp`), a
|
94
|
+
timestamp is generated according to `STAMP_PATTERN`.
|
95
|
+
|
96
|
+
STAMP_PATTERN could be one of followings:
|
97
|
+
|
98
|
+
"20201104172230_078" : full qualified timestamp string
|
99
|
+
"20201104172230" : full qualified timestamp string (no suffix)
|
100
|
+
"202011041722" : year, date and time (omit second part)
|
101
|
+
"11041722" : date and time (omit year and second part)
|
102
|
+
|
103
|
+
This command starts the external editor program to prepare text to
|
104
|
+
store. The editor program will be searched in the following order:
|
105
|
+
|
106
|
+
1. configuration setting of ":editor"
|
107
|
+
2. ENV["EDITOR"]
|
108
|
+
3. "nano"
|
109
|
+
4. "vi"
|
110
|
+
|
111
|
+
If none of the above editor is available, the execution fails.
|
112
|
+
HELP
|
113
|
+
end
|
114
|
+
|
115
|
+
# :stopdoc:
|
116
|
+
private
|
117
|
+
def complement_timestamp_pattern(pattern)
|
118
|
+
stamp_str = nil
|
119
|
+
case pattern.to_s.size
|
120
|
+
when "yyyymoddhhmiss_lll".size, "yyyymoddhhmiss".size
|
121
|
+
stamp_str = pattern.dup
|
122
|
+
when "yyyymoddhhmi".size # omit sec part
|
123
|
+
stamp_str = "#{pattern}00"
|
124
|
+
when "moddhhmi".size # omit year and sec part
|
125
|
+
stamp_str = "#{Time.now.year}#{pattern}00"
|
126
|
+
else
|
127
|
+
raise Textrepo::InvalidTimestampStringError, pattern
|
128
|
+
end
|
129
|
+
stamp_str
|
130
|
+
end
|
48
131
|
end
|
49
132
|
end
|
@@ -1,18 +1,17 @@
|
|
1
|
-
|
1
|
+
module Rbnotes::Commands
|
2
2
|
|
3
|
-
#
|
4
|
-
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
# It does nothing when the specified note does not exist except to
|
10
|
-
# print error message.
|
3
|
+
# Deletes a given note in the repository. The timestamp string must
|
4
|
+
# be a fully qualified one, like "20201016165130". If no argument
|
5
|
+
# was passed, it would try to read from the standard input.
|
6
|
+
#
|
7
|
+
# It does nothing to change the repository when the specified note
|
8
|
+
# does not exist.
|
11
9
|
|
12
|
-
|
10
|
+
class Delete < Command
|
11
|
+
def description # :nodoc:
|
12
|
+
"Delete a note"
|
13
|
+
end
|
13
14
|
|
14
|
-
module Rbnotes
|
15
|
-
class Commands::Delete < Commands::Command
|
16
15
|
def execute(args, conf)
|
17
16
|
stamp = Rbnotes::Utils.read_timestamp(args)
|
18
17
|
|
@@ -27,5 +26,18 @@ module Rbnotes
|
|
27
26
|
puts "Delete [%s]" % stamp.to_s
|
28
27
|
end
|
29
28
|
end
|
29
|
+
|
30
|
+
def help # :nodoc:
|
31
|
+
puts <<HELP
|
32
|
+
usage:
|
33
|
+
#{Rbnotes::NAME} delete [TIMESTAMP]
|
34
|
+
|
35
|
+
Delete a given note. TIMESTAMP must be a fully qualified one, such
|
36
|
+
"20201016165130" or "20201016165130_012" if it has a suffix.
|
37
|
+
|
38
|
+
Delete reads its argument from the standard input when no argument was
|
39
|
+
passed in the command line.
|
40
|
+
HELP
|
41
|
+
end
|
30
42
|
end
|
31
43
|
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require "pathname"
|
2
|
+
|
3
|
+
module Rbnotes::Commands
|
4
|
+
|
5
|
+
##
|
6
|
+
# Writes out a given note into a specified file. The file will be
|
7
|
+
# created in the current working directory unless an absolute path
|
8
|
+
# is specified as a filename.
|
9
|
+
#
|
10
|
+
# When no argument was passed, would try to read a timestamp string
|
11
|
+
# from the standard input.
|
12
|
+
|
13
|
+
class Export < Command
|
14
|
+
|
15
|
+
def description # :nodoc:
|
16
|
+
"Write out a note into a file"
|
17
|
+
end
|
18
|
+
|
19
|
+
#
|
20
|
+
# :call-seq:
|
21
|
+
# execute([a String as timestring], Rbnotes::Conf or Hash) -> nil
|
22
|
+
|
23
|
+
def execute(args, conf)
|
24
|
+
stamp = Rbnotes::Utils.read_timestamp(args)
|
25
|
+
|
26
|
+
repo = Textrepo.init(conf)
|
27
|
+
begin
|
28
|
+
content = repo.read(stamp)
|
29
|
+
rescue Textrepo::MissingTimestampError => _
|
30
|
+
raise MissingTimestampError, stamp
|
31
|
+
end
|
32
|
+
|
33
|
+
pathname = Pathname.new(args.shift || "#{stamp}.md")
|
34
|
+
pathname.parent.mkpath
|
35
|
+
pathname.open("w"){ |f| f.puts content }
|
36
|
+
puts "Export a note [%s] into a file [%s]" % [stamp, pathname]
|
37
|
+
end
|
38
|
+
|
39
|
+
def help # :nodoc:
|
40
|
+
puts <<HELP
|
41
|
+
usage:
|
42
|
+
#{Rbnotes::NAME} export [TIMESTAMP [FILENAME]]
|
43
|
+
|
44
|
+
Write out a given note into a specified file. TIMESTAMP must be a
|
45
|
+
fully qualified one, such "20201108141600", or "20201108141600_012" if
|
46
|
+
it has a suffix. FILENAME is optional. When it omitted, the filename
|
47
|
+
would be a timestamp string with ".md" as its extension, such
|
48
|
+
"20201108141600.md"
|
49
|
+
|
50
|
+
The file will be created into the current working directory unless an
|
51
|
+
absolute path is specified as FILENAME.
|
52
|
+
|
53
|
+
When no argument was passed, it would try to read a timestamp string
|
54
|
+
from the standard input. Then, FILENAME would be regarded as omitted.
|
55
|
+
HELP
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
module Rbnotes::Commands
|
2
|
+
|
3
|
+
##
|
4
|
+
# Shows help message for the command which specifies with the
|
5
|
+
# argument.
|
6
|
+
|
7
|
+
class Help < Command
|
8
|
+
|
9
|
+
def description # :nodoc:
|
10
|
+
"Provide help on each command"
|
11
|
+
end
|
12
|
+
|
13
|
+
##
|
14
|
+
# :call-seq:
|
15
|
+
# execute(["add"], Rbnotes::Conf or Hash) -> nil
|
16
|
+
# execute(["delete"], Rbnotes::Conf or Hash) -> nil
|
17
|
+
|
18
|
+
def execute(args, conf)
|
19
|
+
cmd_name = args.shift
|
20
|
+
case cmd_name
|
21
|
+
when nil
|
22
|
+
self.help
|
23
|
+
when "commands"
|
24
|
+
print_commands
|
25
|
+
else
|
26
|
+
Commands.load(cmd_name).help
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def help # :nodoc:
|
31
|
+
puts <<HELP
|
32
|
+
#{Rbnotes::NAME.capitalize} is a simple tool to write a note into a single repository.
|
33
|
+
|
34
|
+
When creates a new note, a timestamp is attached to the note. #{Rbnotes::NAME.capitalize}
|
35
|
+
manages notes with those timestamps, such update, delete, ...etc.
|
36
|
+
|
37
|
+
Timestamp is a series of digits which represents year, date, and time.
|
38
|
+
It looks like "20201106121100", means "2020-11-06 12:11:00". It is
|
39
|
+
generated in the local time.
|
40
|
+
|
41
|
+
usage:
|
42
|
+
#{Rbnotes::NAME} [option] [command] [args]
|
43
|
+
|
44
|
+
option:
|
45
|
+
-c, --conf [CONF_FILE] : specifiy the configuration file
|
46
|
+
-v, --version : print version
|
47
|
+
-h, --help : show this message
|
48
|
+
|
49
|
+
CONF_FILE must be written in YAML. To know about details of the
|
50
|
+
configuration file, see README.md or Wiki page.
|
51
|
+
|
52
|
+
Further help:
|
53
|
+
#{Rbnotes::NAME} help commands
|
54
|
+
#{Rbnotes::NAME} help COMMAND
|
55
|
+
#{Rbnotes::NAME} usage
|
56
|
+
|
57
|
+
Further information:
|
58
|
+
https://github.com/mnbi/rbnotes/wiki
|
59
|
+
HELP
|
60
|
+
end
|
61
|
+
|
62
|
+
# :stopdoc:
|
63
|
+
private
|
64
|
+
|
65
|
+
def print_commands
|
66
|
+
Dir.glob("*.rb", :base => __dir__) { |rb|
|
67
|
+
next if rb == "help.rb"
|
68
|
+
require_relative rb
|
69
|
+
}
|
70
|
+
commands = Commands.constants.difference([:Builtins, :Command])
|
71
|
+
builtins = Commands::Builtins.constants
|
72
|
+
|
73
|
+
puts "#{Rbnotes::NAME.capitalize} Commands:"
|
74
|
+
print_commands_desc(commands.sort)
|
75
|
+
puts
|
76
|
+
puts "for development purpose"
|
77
|
+
print_builtins_desc(builtins.sort)
|
78
|
+
end
|
79
|
+
|
80
|
+
def print_commands_desc(commands)
|
81
|
+
print_desc(Commands, commands)
|
82
|
+
end
|
83
|
+
|
84
|
+
def print_builtins_desc(builtins)
|
85
|
+
print_desc(Commands::Builtins, builtins)
|
86
|
+
end
|
87
|
+
|
88
|
+
def print_desc(mod, commands)
|
89
|
+
commands.map { |cmd|
|
90
|
+
name = "#{cmd.to_s.downcase} "[0, 8]
|
91
|
+
desc = mod.const_get(cmd, false).new.description
|
92
|
+
puts " #{name} #{desc}"
|
93
|
+
}
|
94
|
+
end
|
95
|
+
|
96
|
+
# :startdoc:
|
97
|
+
end
|
98
|
+
end
|
@@ -1,5 +1,29 @@
|
|
1
|
-
module Rbnotes
|
2
|
-
|
1
|
+
module Rbnotes::Commands
|
2
|
+
|
3
|
+
##
|
4
|
+
# Imports a existing file which specified by the argument as a note.
|
5
|
+
#
|
6
|
+
# A timestamp is generated referring to the birthtime of the given
|
7
|
+
# file. If birthtime is not available on the system, use mtime
|
8
|
+
# (modification time).
|
9
|
+
#
|
10
|
+
# Occasionally, there is another note which has the same timestmap
|
11
|
+
# in the repository. Then, tries to create a new timestamp with a
|
12
|
+
# suffix. Unluckily, when such timestamp with a suffix already
|
13
|
+
# exists, tries to create a new one with increasing suffix. Suffix
|
14
|
+
# will be "001", "002", ..., or "999". In worst case, all suffix
|
15
|
+
# might have been already used. Then, abandons to import.
|
16
|
+
|
17
|
+
class Import < Command
|
18
|
+
|
19
|
+
def description # :nodoc:
|
20
|
+
"Import a file as a note"
|
21
|
+
end
|
22
|
+
|
23
|
+
##
|
24
|
+
# :call-seq:
|
25
|
+
# execute([PATHNAME], Rbnotes::Conf or Hash) -> nil
|
26
|
+
|
3
27
|
def execute(args, conf)
|
4
28
|
file = args.shift
|
5
29
|
unless file.nil?
|
@@ -58,5 +82,18 @@ module Rbnotes
|
|
58
82
|
super
|
59
83
|
end
|
60
84
|
end
|
85
|
+
|
86
|
+
def help # :nodoc:
|
87
|
+
puts <<HELP
|
88
|
+
usage:
|
89
|
+
#{Rbnotes::NAME} import FILE
|
90
|
+
|
91
|
+
Imports a existing file which specified by the argument as a note.
|
92
|
+
|
93
|
+
A timestamp is generated referring to the birthtime of the given file.
|
94
|
+
If birthtime is not available on the system, use mtime (modification
|
95
|
+
time).
|
96
|
+
HELP
|
97
|
+
end
|
61
98
|
end
|
62
99
|
end
|
@@ -1,22 +1,27 @@
|
|
1
|
+
require "date"
|
1
2
|
require "unicode/display_width"
|
2
3
|
require "io/console/size"
|
3
4
|
|
4
|
-
module Rbnotes
|
5
|
+
module Rbnotes::Commands
|
6
|
+
|
5
7
|
##
|
6
8
|
# Defines `list` command for `rbnotes`. See the document of execute
|
7
9
|
# method to know about the behavior of this command.
|
8
10
|
|
9
|
-
class
|
11
|
+
class List < Command
|
12
|
+
|
13
|
+
def description # :nodoc:
|
14
|
+
"List notes"
|
15
|
+
end
|
10
16
|
|
11
17
|
##
|
12
|
-
# Shows
|
18
|
+
# Shows a list of notes in the repository. The only argument is
|
13
19
|
# optional. If it passed, it must be an timestamp pattern. A
|
14
20
|
# timestamp is an instance of Textrepo::Timestamp class. A
|
15
21
|
# timestamp pattern is a string which would match several
|
16
22
|
# Timestamp objects.
|
17
23
|
#
|
18
|
-
# Here is
|
19
|
-
# several examples of timestamp patterns.
|
24
|
+
# Here is several examples of timestamp patterns.
|
20
25
|
#
|
21
26
|
# "20201027093600_012": a complete string to represent a timestamp
|
22
27
|
# - this pattern would match exactly one Timestamp object
|
@@ -24,6 +29,9 @@ module Rbnotes
|
|
24
29
|
# "20201027": specifies year and date
|
25
30
|
# - all Timestamps those have the same year and date would match
|
26
31
|
#
|
32
|
+
# "202011": specifies year and month
|
33
|
+
# - all Timestamps those have the same year and month would match
|
34
|
+
#
|
27
35
|
# "2020": specifies year only
|
28
36
|
# - all Timestamps those have the same year would match
|
29
37
|
#
|
@@ -35,16 +43,61 @@ module Rbnotes
|
|
35
43
|
# execute(Array, Rbnotes::Conf or Hash) -> nil
|
36
44
|
|
37
45
|
def execute(args, conf)
|
38
|
-
|
46
|
+
arg = args.shift
|
47
|
+
patterns = []
|
48
|
+
|
49
|
+
case arg.to_s
|
50
|
+
when "today", "to"
|
51
|
+
patterns << Textrepo::Timestamp.new(Time.now).to_s[0..7]
|
52
|
+
when "yesterday", "ye"
|
53
|
+
t = Time.now
|
54
|
+
patterns << Date.new(t.year, t.mon, t.day).prev_day.strftime("%Y%m%d")
|
55
|
+
when "this_week", "tw"
|
56
|
+
patterns.concat(dates_in_this_week)
|
57
|
+
when "last_week", "lw"
|
58
|
+
patterns.concat(dates_in_last_week)
|
59
|
+
else
|
60
|
+
patterns << arg
|
61
|
+
end
|
39
62
|
|
40
63
|
@repo = Textrepo.init(conf)
|
64
|
+
stamps = patterns.map { |pat|
|
65
|
+
@repo.entries(pat).sort{|a, b| b <=> a}
|
66
|
+
}.flatten
|
41
67
|
# newer stamp shoud be above
|
42
|
-
stamps = @repo.entries(pattern).sort{|a, b| b <=> a}
|
43
68
|
stamps.each { |timestamp|
|
44
69
|
puts make_headline(timestamp)
|
45
70
|
}
|
46
71
|
end
|
47
72
|
|
73
|
+
def help # :nodoc:
|
74
|
+
puts <<HELP
|
75
|
+
usage:
|
76
|
+
#{Rbnotes::NAME} list [STAMP_PATTERN|KEYWORD]
|
77
|
+
|
78
|
+
Show a list of notes. When no arguments, make a list with all notes
|
79
|
+
in the repository. When specified STAMP_PATTERN, only those match the
|
80
|
+
pattern are listed. Instead of STAMP_PATTERN, some KEYWORDs could be
|
81
|
+
used.
|
82
|
+
|
83
|
+
STAMP_PATTERN must be:
|
84
|
+
|
85
|
+
(a) full qualified timestamp (with suffix): "20201030160200"
|
86
|
+
(b) year and date part: "20201030"
|
87
|
+
(c) year and month part: "202010"
|
88
|
+
(d) year part only: "2020"
|
89
|
+
(e) date part only: "1030"
|
90
|
+
|
91
|
+
KEYWORD:
|
92
|
+
|
93
|
+
- "today" (or "to")
|
94
|
+
- "yeasterday" (or "ye")
|
95
|
+
- "this_week" (or "tw")
|
96
|
+
- "last_week" (or "lw")
|
97
|
+
|
98
|
+
HELP
|
99
|
+
end
|
100
|
+
|
48
101
|
# :stopdoc:
|
49
102
|
|
50
103
|
private
|
@@ -92,6 +145,29 @@ module Rbnotes
|
|
92
145
|
str.sub(/^#+ +/, '')
|
93
146
|
end
|
94
147
|
|
148
|
+
# week day for Monday start calendar
|
149
|
+
def wday(time)
|
150
|
+
(time.wday - 1) % 7
|
151
|
+
end
|
152
|
+
|
153
|
+
def dates_in_this_week
|
154
|
+
to = Time.now
|
155
|
+
start = Date.new(to.year, to.mon, to.day).prev_day(wday(to))
|
156
|
+
dates_in_week(start)
|
157
|
+
end
|
158
|
+
|
159
|
+
def dates_in_last_week
|
160
|
+
to = Time.now
|
161
|
+
start_of_this_week = Date.new(to.year, to.mon, to.day).prev_day(wday(to))
|
162
|
+
dates_in_week(start_of_this_week.prev_day(7))
|
163
|
+
end
|
164
|
+
|
165
|
+
def dates_in_week(start_date)
|
166
|
+
dates = [start_date]
|
167
|
+
1.upto(6) { |i| dates << start_date.next_day(i) }
|
168
|
+
dates.map { |d| d.strftime("%Y%m%d") }
|
169
|
+
end
|
170
|
+
|
95
171
|
# :startdoc:
|
96
172
|
end
|
97
173
|
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module Rbnotes::Commands
|
2
|
+
|
3
|
+
##
|
4
|
+
# Searches a given pattern in notes those have timestamps match a
|
5
|
+
# given timestamp pattern. The first argument is a pattern to search.
|
6
|
+
# It is a String object represents a portion of text or it may a
|
7
|
+
# String represents a regular expression. The second argument is
|
8
|
+
# optional and it is a timestamp pattern to specify the search target.
|
9
|
+
#
|
10
|
+
# A pattern for search is mandatory. If no pattern, raises
|
11
|
+
# Rbnotes::MissingArgumentError.
|
12
|
+
#
|
13
|
+
# Example of PATTERN for search:
|
14
|
+
#
|
15
|
+
# "rbnotes" (a word)
|
16
|
+
# "macOS Big Sur" (a few words)
|
17
|
+
# "2[0-9]{3}(0[1-9]|1[0-2])(0[1-9]|[12][0-9]|3[01])" (a regular expression)
|
18
|
+
#
|
19
|
+
# A timestamp pattern is optional. If no timestamp pattern, all notes
|
20
|
+
# in the repository would be target of search.
|
21
|
+
#
|
22
|
+
# See the document of `Rbnotes::Commands::List#execute` to know about
|
23
|
+
# a timestamp pattern.
|
24
|
+
|
25
|
+
class Search < Command
|
26
|
+
|
27
|
+
def description # :nodoc:
|
28
|
+
"Search a given pattern in notes"
|
29
|
+
end
|
30
|
+
|
31
|
+
def execute(args, conf)
|
32
|
+
pattern = args.shift
|
33
|
+
raise MissingArgumentError, args if pattern.nil?
|
34
|
+
|
35
|
+
timestamp_pattern = args.shift # `nil` is acceptable
|
36
|
+
|
37
|
+
repo = Textrepo.init(conf)
|
38
|
+
begin
|
39
|
+
result = repo.search(pattern, timestamp_pattern)
|
40
|
+
rescue Textrepo::InvalidSearchResultError => e
|
41
|
+
puts e.message
|
42
|
+
else
|
43
|
+
result.each { |stamp, num, match|
|
44
|
+
puts "#{stamp}:#{num}:#{match}"
|
45
|
+
}
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def help # :nodoc:
|
50
|
+
puts <<HELP
|
51
|
+
usage:
|
52
|
+
#{Rbnotes::NAME} search PATTERN [STAMP_PATTERN]
|
53
|
+
|
54
|
+
PATTERN is a word (or words) to search, it may also be a regular
|
55
|
+
expression.
|
56
|
+
|
57
|
+
STAMP_PATTERN must be:
|
58
|
+
|
59
|
+
(a) full qualified timestamp (with suffix): "20201030160200"
|
60
|
+
(b) year and date part: "20201030"
|
61
|
+
(c) year and month part: "202010"
|
62
|
+
(d) year part only: "2020"
|
63
|
+
(e) date part only: "1030"
|
64
|
+
HELP
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -1,5 +1,23 @@
|
|
1
|
-
module Rbnotes
|
2
|
-
|
1
|
+
module Rbnotes::Commands
|
2
|
+
|
3
|
+
##
|
4
|
+
# Shows the content of the note specified by the argument. The
|
5
|
+
# argument must be a string which can be converted into
|
6
|
+
# Textrepo::Timestamp object.
|
7
|
+
#
|
8
|
+
# A string for Timestamp must be:
|
9
|
+
#
|
10
|
+
# "20201106112600" : year, date, time and sec
|
11
|
+
# "20201106112600_012" : with suffix
|
12
|
+
#
|
13
|
+
# If no argument is passed, reads the standard input for an argument.
|
14
|
+
|
15
|
+
class Show < Command
|
16
|
+
|
17
|
+
def description # :nodoc:
|
18
|
+
"Show the content of a note"
|
19
|
+
end
|
20
|
+
|
3
21
|
def execute(args, conf)
|
4
22
|
stamp = Rbnotes::Utils.read_timestamp(args)
|
5
23
|
|
@@ -17,5 +35,18 @@ module Rbnotes
|
|
17
35
|
puts content
|
18
36
|
end
|
19
37
|
end
|
38
|
+
|
39
|
+
def help # :nodoc:
|
40
|
+
puts <<HELP
|
41
|
+
usage:
|
42
|
+
#{Rbnotes::NAME} show [TIMESTAMP]
|
43
|
+
|
44
|
+
Show the content of given note. TIMESTAMP must be a fully qualified
|
45
|
+
one, such "20201016165130" or "20201016165130_012" if it has a suffix.
|
46
|
+
|
47
|
+
The command try to read its argument from the standard input when no
|
48
|
+
argument was passed in the command line.
|
49
|
+
HELP
|
50
|
+
end
|
20
51
|
end
|
21
52
|
end
|
@@ -1,37 +1,49 @@
|
|
1
1
|
module Rbnotes::Commands
|
2
|
+
|
2
3
|
##
|
3
4
|
# Updates the content of the note associated with given timestamp.
|
4
|
-
#
|
5
|
+
#
|
6
|
+
# Reads its argument from the standard input when no argument was
|
7
|
+
# passed in the command line.
|
8
|
+
#
|
5
9
|
# The timestamp associated with the note will be updated to new one,
|
6
10
|
# which is generated while the command exection.
|
7
11
|
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
# repository. When the given timestamp was not found, the command
|
11
|
-
# fails.
|
12
|
-
#
|
13
|
-
# Timestamp which is associated to the target note will be newly
|
14
|
-
# generated with the command execution time. That is, the timestamp
|
15
|
-
# before the command exection will be obsolete.
|
12
|
+
# When "-k" (or "--keep") option is specified, the timestamp will
|
13
|
+
# remain unchanged.
|
16
14
|
#
|
17
|
-
#
|
18
|
-
# content of the note. The editor program will be searched as same
|
19
|
-
# as add command.
|
15
|
+
# Actual modification is done interactively by the external editor.
|
20
16
|
#
|
21
|
-
#
|
17
|
+
# The editor program will be searched as same as add command. If
|
18
|
+
# none of editors is available, the execution fails.
|
22
19
|
|
23
20
|
class Update < Command
|
24
21
|
include ::Rbnotes::Utils
|
25
22
|
|
23
|
+
def description # :nodoc:
|
24
|
+
"Update the content of a note"
|
25
|
+
end
|
26
|
+
|
26
27
|
##
|
27
28
|
# The 1st and only one argument is the timestamp to speficy the
|
28
|
-
# note to update.
|
29
|
-
# to the note updated.
|
29
|
+
# note to update.
|
30
30
|
#
|
31
31
|
# :call-seq:
|
32
32
|
# "20201020112233" -> "20201021123400"
|
33
33
|
|
34
34
|
def execute(args, conf)
|
35
|
+
@opts = {}
|
36
|
+
while args.size > 0
|
37
|
+
arg = args.shift
|
38
|
+
case arg
|
39
|
+
when "-k", "--keep"
|
40
|
+
@opts[:keep_timestamp] = true
|
41
|
+
else
|
42
|
+
args.unshift(arg)
|
43
|
+
break
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
35
47
|
target_stamp = Rbnotes::Utils.read_timestamp(args)
|
36
48
|
editor = find_editor(conf[:editor])
|
37
49
|
repo = Textrepo.init(conf)
|
@@ -44,16 +56,21 @@ module Rbnotes::Commands
|
|
44
56
|
end
|
45
57
|
|
46
58
|
tmpfile = run_with_tmpfile(editor, target_stamp.to_s, text)
|
47
|
-
text = File.readlines(tmpfile)
|
59
|
+
text = File.readlines(tmpfile, :chomp => true)
|
48
60
|
|
49
61
|
unless text.empty?
|
62
|
+
keep = @opts[:keep_timestamp] || false
|
50
63
|
newstamp = nil
|
51
64
|
begin
|
52
|
-
newstamp = repo.update(target_stamp, text)
|
65
|
+
newstamp = repo.update(target_stamp, text, keep)
|
53
66
|
rescue StandardError => e
|
54
67
|
puts e.message
|
55
68
|
else
|
56
|
-
|
69
|
+
if keep
|
70
|
+
puts "Update the note content, the timestamp unchanged [%s]" % newstamp
|
71
|
+
else
|
72
|
+
puts "Update the note [%s -> %s]" % [target_stamp, newstamp] unless target_stamp == newstamp
|
73
|
+
end
|
57
74
|
ensure
|
58
75
|
# Don't forget to remove the temporary file.
|
59
76
|
File.delete(tmpfile)
|
@@ -62,5 +79,27 @@ module Rbnotes::Commands
|
|
62
79
|
puts "Nothing is updated, since the specified content is empty."
|
63
80
|
end
|
64
81
|
end
|
82
|
+
|
83
|
+
def help # :nodoc:
|
84
|
+
puts <<HELP
|
85
|
+
usage:
|
86
|
+
#{Rbnotes::NAME} update [TIMESTAMP]
|
87
|
+
|
88
|
+
Updates the content of the note associated with given timestamp.
|
89
|
+
|
90
|
+
Reads its argument from the standard input when no argument was passed
|
91
|
+
in the command line.
|
92
|
+
|
93
|
+
The timestamp associated with the note will be updated to new one,
|
94
|
+
which is generated while the command exection.
|
95
|
+
|
96
|
+
When "-k" (or "--keep") option is specified, the timestamp will remain
|
97
|
+
unchanged.
|
98
|
+
|
99
|
+
Actual modification is done interactively by the external editor. The
|
100
|
+
editor program will be searched as same as add command. If none of
|
101
|
+
editors is available, the execution fails.
|
102
|
+
HELP
|
103
|
+
end
|
65
104
|
end
|
66
105
|
end
|
data/lib/rbnotes/utils.rb
CHANGED
@@ -113,7 +113,11 @@ module Rbnotes
|
|
113
113
|
# foo bar baz ...
|
114
114
|
#
|
115
115
|
# then, only the first string is interested
|
116
|
-
|
116
|
+
begin
|
117
|
+
io.gets.split(":")[0].rstrip
|
118
|
+
rescue NoMethodError => _
|
119
|
+
nil
|
120
|
+
end
|
117
121
|
end
|
118
122
|
module_function :read_arg
|
119
123
|
|
data/lib/rbnotes/version.rb
CHANGED
data/rbnotes.gemspec
CHANGED
@@ -25,6 +25,6 @@ Gem::Specification.new do |spec|
|
|
25
25
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
26
26
|
spec.require_paths = ["lib"]
|
27
27
|
|
28
|
-
spec.add_dependency "textrepo", "~> 0.4"
|
28
|
+
spec.add_dependency "textrepo", "~> 0.5.4"
|
29
29
|
spec.add_dependency "unicode-display_width", "~> 1.7"
|
30
30
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rbnotes
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- mnbi
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-11-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: textrepo
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 0.5.4
|
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:
|
26
|
+
version: 0.5.4
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: unicode-display_width
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -64,8 +64,11 @@ files:
|
|
64
64
|
- lib/rbnotes/commands.rb
|
65
65
|
- lib/rbnotes/commands/add.rb
|
66
66
|
- lib/rbnotes/commands/delete.rb
|
67
|
+
- lib/rbnotes/commands/export.rb
|
68
|
+
- lib/rbnotes/commands/help.rb
|
67
69
|
- lib/rbnotes/commands/import.rb
|
68
70
|
- lib/rbnotes/commands/list.rb
|
71
|
+
- lib/rbnotes/commands/search.rb
|
69
72
|
- lib/rbnotes/commands/show.rb
|
70
73
|
- lib/rbnotes/commands/update.rb
|
71
74
|
- lib/rbnotes/conf.rb
|