rbnotes 0.4.11 → 0.4.12

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4170ccc84305971d10f3726351cdc4138b5fabaa7293bc10a827ed0458f28b8c
4
- data.tar.gz: 291efc32e2e65462e8c6996ecbbc7ffbb4e6887a5d0065bbb843d01dfbb8c78c
3
+ metadata.gz: 517b5866c81f76286f87b2ed7d2e695c4dd09d5c7ab86f9557079232a58fde37
4
+ data.tar.gz: 1d89412445d155501f67cd0978a8070975ed722ee7440119cf5a9ba89ca946eb
5
5
  SHA512:
6
- metadata.gz: 1f6d2659c1a50f462867a53bff3f7b45e8b38035c3af44407b70d359c6af9409481f1033059384bd8d6b42d03981ce4f955ac87ee5fe7e99f5b50465d47f4e1b
7
- data.tar.gz: f5949cfe44eef0951a80ec8949b6bb8a3440d5b483ddacdaf652d8b4dd258a7eb53db42c40290e9a2ebd6e3a1bf6e204f2382b41dd40b23ac8b271dd05547672
6
+ metadata.gz: 1f0bab361e6f4a7f22a59433369b221b6dffc1e16b79f9d4bdc4027d78c3d61a6e949ab2b81ae1ab3be4c5d52af6bd74aed4b36c70a93f31e710a42b7bb23731
7
+ data.tar.gz: af38ba13276090ae653fee8b1b3f67f3de57596851ce8b645f4ed3463c38d71c4a950b3382bff55ad98853c42e2cb3f2df0e7e7652f756f385d53ef15f917085
@@ -5,6 +5,19 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/)
5
5
  and this project adheres to [Semantic Versioning](https://semver.org/).
6
6
 
7
7
  ## [Unreleased]
8
+ Nothing to record here.
9
+
10
+ ## [0.4.12] - 2020-12-18
11
+ ### Changed
12
+ - Make clear the spec of `list` command args. (#94)
13
+ - Add a feature to use a template file for `add` command. (#87)
14
+ - Add new keywords for `list` command. (#90)
15
+ - `this_month` and `last_month`
16
+ - Add a new option, `verbose` for `list` command. (#76)
17
+
18
+ ### Fixed
19
+ - Fix issue #80: suppress unnecessary error message.
20
+
8
21
  ## [0.4.11] - 2020-12-07
9
22
  ### Added
10
23
  - Add a new command `statistics`. (#73)
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rbnotes (0.4.11)
4
+ rbnotes (0.4.12)
5
5
  textrepo (~> 0.5.4)
6
6
  unicode-display_width (~> 1.7)
7
7
 
@@ -5,4 +5,5 @@
5
5
  :repository_base: "~"
6
6
  :pager: "bat -l md"
7
7
  :picker: "fzf"
8
+ :picker_option: "-m"
8
9
  :editor: "/usr/local/bin/emacsclient"
@@ -5,4 +5,5 @@
5
5
  :repository_base: "tmp"
6
6
  :pager: "bat -l md"
7
7
  :picker: "fzf"
8
+ :picker_option: "-m"
8
9
  :editor: "/usr/local/bin/emacsclient"
@@ -0,0 +1,8 @@
1
+ ---
2
+ :run_mode: :development
3
+ :repository_type: :file_system
4
+ :repository_name: "notes"
5
+ :repository_base: "tmp"
6
+ :pager: "bat -l md"
7
+ :picker: "fzf"
8
+ :editor: "/usr/local/bin/emacsclient"
@@ -0,0 +1,7 @@
1
+ ---
2
+ :run_mode: :development
3
+ :repository_type: :file_system
4
+ :repository_name: "notes"
5
+ :repository_base: "tmp"
6
+ :pager: "bat -l md"
7
+ :editor: "/usr/local/bin/emacsclient"
@@ -0,0 +1,8 @@
1
+ ---
2
+ :run_mode: :development
3
+ :repository_type: :file_system
4
+ :repository_name: "notes"
5
+ :repository_base: "tmp"
6
+ :pager: "bat -l md"
7
+ :picker: "peco"
8
+ :editor: "/usr/local/bin/emacsclient"
@@ -48,16 +48,24 @@ app = App.new
48
48
  begin
49
49
  app.parse_global_options(ARGV)
50
50
  app.run(ARGV)
51
- rescue Errno::EPIPE => e
51
+ rescue Errno::EPIPE => _
52
52
  # Fix issue #61: When the pipeline which rbnotes connects is
53
53
  # discarded by the other program, the execption was raised. It does
54
54
  # not end abnormally for rbnotes. So, just ignores the exception.
55
55
  exit 0
56
+ rescue NoArgumentError => _
57
+ # Fix issue #80: Typically, this error raises when a command tries
58
+ # to read the standard input for its arguments and gets nil. It
59
+ # means user wants to cancel to execute. So, just ignore the error
60
+ # and exit.
61
+ exit 0
56
62
  rescue MissingArgumentError, MissingTimestampError,
57
63
  NoEditorError, ProgramAbortError,
58
64
  Textrepo::InvalidTimestampStringError,
59
65
  InvalidTimestampPatternError,
66
+ InvalidTimestampPatternAsDateError,
60
67
  NoConfFileError,
68
+ NoTemplateFileError,
61
69
  ArgumentError,
62
70
  Errno::EACCES => e
63
71
  puts e.message
@@ -42,6 +42,9 @@ module Rbnotes::Commands
42
42
  raise ArgumentError, "missing timestamp: %s" % args.unshift(arg) if stamp_str.nil?
43
43
  stamp_str = complement_timestamp_pattern(stamp_str)
44
44
  @opts[:timestamp] = Textrepo::Timestamp.parse_s(stamp_str)
45
+ when "-f", "--template-file"
46
+ template_path = args.shift
47
+ @opts[:template] = template_path
45
48
  else
46
49
  args.unshift(arg)
47
50
  break
@@ -54,7 +57,8 @@ module Rbnotes::Commands
54
57
  editor = Rbnotes.utils.find_program(candidates)
55
58
  raise Rbnotes::NoEditorError, candidates if editor.nil?
56
59
 
57
- tmpfile = Rbnotes.utils.run_with_tmpfile(editor, stamp.to_s)
60
+ template = read_template(conf)
61
+ tmpfile = Rbnotes.utils.run_with_tmpfile(editor, stamp.to_s, template)
58
62
 
59
63
  unless FileTest.exist?(tmpfile)
60
64
  puts "Cancel adding, since nothing to store"
@@ -127,5 +131,26 @@ HELP
127
131
  end
128
132
  stamp_str
129
133
  end
134
+
135
+ def read_template(conf)
136
+ template = nil
137
+ template_path = @opts[:template] || conf[:template]
138
+
139
+ if template_path
140
+ raise Rbnotes::NoTemplateFileError, template_path unless FileTest.exist?(template_path)
141
+ template = File.readlines(template_path, chomp: true)
142
+ else
143
+ template_path = default_template_file(conf)
144
+ template = File.readlines(template_path, chomp: true) if FileTest.exist?(template_path)
145
+ end
146
+
147
+ template
148
+ end
149
+
150
+ def default_template_file(conf)
151
+ dir = File.join(conf[:config_home], "templates")
152
+ File.expand_path("default.md", dir)
153
+ end
154
+
130
155
  end
131
156
  end
@@ -24,10 +24,12 @@ module Rbnotes::Commands
24
24
  #
25
25
  # A keyword must be one of them:
26
26
  #
27
- # - "today" (or "to")
28
- # - "yeasterday" (or "ye")
29
- # - "this_week" (or "tw")
30
- # - "last_week" (or "lw")
27
+ # - "today" (or "to")
28
+ # - "yeasterday" (or "ye")
29
+ # - "this_week" (or "tw")
30
+ # - "last_week" (or "lw")
31
+ # - "this_month" (or "tm")
32
+ # - "last_month" (or "lm")
31
33
  #
32
34
  # Here is several examples of timestamp patterns.
33
35
  #
@@ -57,6 +59,8 @@ module Rbnotes::Commands
57
59
  case arg
58
60
  when "-w", "--week"
59
61
  @opts[:enum_week] = true
62
+ when "-v", "--verbose"
63
+ @opts[:verbose] = true
60
64
  else
61
65
  args.unshift(arg)
62
66
  break
@@ -70,20 +74,41 @@ module Rbnotes::Commands
70
74
  when "yyyymodd".size, "yyyymoddhhmiss".size, "yyyymoddhhmiss_sfx".size
71
75
  stamp_str = "#{arg}000000"[0, 14]
72
76
  timestamp = Textrepo::Timestamp.parse_s(stamp_str)
73
- patterns = Rbnotes.utils.timestamp_patterns_in_week(timestamp)
77
+ when "modd".size
78
+ this_year = Time.now.year.to_s
79
+ stamp_str = "#{this_year}#{arg}000000"
80
+ begin
81
+ timestamp = Textrepo::Timestamp.parse_s(stamp_str)
82
+ rescue Textrepo::InvalidTimestampStringError => _e
83
+ raise InvalidTimestampPatternAsDateError, arg
84
+ end
74
85
  else
75
- raise InvalidTimestampPatternError,
76
- "cannot convert to a date [%s]" % args.unshift(arg)
86
+ raise InvalidTimestampPatternAsDateError, args.unshift(arg)
77
87
  end
88
+ patterns = Rbnotes.utils.timestamp_patterns_in_week(timestamp)
78
89
  else
79
90
  patterns = Rbnotes.utils.expand_keyword_in_args(args)
80
91
  end
81
92
 
82
93
  @repo = Textrepo.init(conf)
83
- # newer stamp shoud be above
84
- Rbnotes.utils.find_notes(patterns, @repo).each { |timestamp|
85
- puts Rbnotes.utils.make_headline(timestamp, @repo.read(timestamp))
86
- }
94
+ notes = Rbnotes.utils.find_notes(patterns, @repo)
95
+ output = []
96
+ if @opts[:verbose]
97
+ collect_timestamps_by_date(notes).each { |date, timestamps|
98
+ output << "#{date} (#{timestamps.size})"
99
+ timestamps.each { |timestamp|
100
+ pad = " "
101
+ output << Rbnotes.utils.make_headline(timestamp,
102
+ @repo.read(timestamp), pad)
103
+ }
104
+ }
105
+ else
106
+ notes.each { |timestamp|
107
+ output << Rbnotes.utils.make_headline(timestamp,
108
+ @repo.read(timestamp))
109
+ }
110
+ end
111
+ puts output
87
112
  end
88
113
 
89
114
  def help # :nodoc:
@@ -110,6 +135,8 @@ KEYWORD:
110
135
  - "yeasterday" (or "ye")
111
136
  - "this_week" (or "tw")
112
137
  - "last_week" (or "lw")
138
+ - "this_month" (or "tm")
139
+ - "last_month" (or "lm")
113
140
 
114
141
  An option "--week" is also acceptable. It specifies to enumerate all
115
142
  days of a week. Typically, the option is used with a STAMP_PATTERN
@@ -124,5 +151,24 @@ would be as same as the KEYWORD, "this_week" was specified.
124
151
  HELP
125
152
  end
126
153
 
154
+ # :stopdoc:
155
+
156
+ private
157
+
158
+ def collect_timestamps_by_date(timestamps)
159
+ result = {}
160
+ timestamps.map { |ts|
161
+ [ts.strftime("%Y-%m-%d"), ts]
162
+ }.reduce(result) { |r, pair|
163
+ date, stamp = pair
164
+ r[date] ||= []
165
+ r[date] << stamp
166
+ r
167
+ }
168
+ result
169
+ end
170
+
171
+ # :startdoc:
172
+
127
173
  end
128
174
  end
@@ -20,8 +20,12 @@ module Rbnotes::Commands
20
20
 
21
21
  picker = conf[:picker]
22
22
  unless picker.nil?
23
+ picker_opts = conf[:picker_option]
24
+ cmds = [picker]
25
+ cmds.concat(picker_opts.split) unless picker_opts.nil?
26
+
23
27
  require 'open3'
24
- result = Open3.pipeline_rw(picker) { |stdin, stdout, _|
28
+ result = Open3.pipeline_rw(cmds) { |stdin, stdout, _|
25
29
  stdin.puts list
26
30
  stdin.close
27
31
  stdout.read
@@ -31,19 +31,26 @@ module Rbnotes
31
31
 
32
32
  DIRNAME_COMMON_CONF = ".config"
33
33
 
34
- def initialize(conf_path = nil) # :nodoc:
35
- @conf_path = conf_path
34
+ def initialize(path = nil) # :nodoc:
36
35
  @conf = {}
37
36
 
38
- if use_default_values?
39
- @conf.merge!(DEFAULT_VALUES)
37
+ unless path.nil?
38
+ abspath = File.expand_path(path)
39
+ raise NoConfFileError, path unless FileTest.exist?(abspath)
40
+ @conf[:path] = abspath
40
41
  else
41
- @conf_path ||= default_conf_file
42
- raise NoConfFileError, @conf_path unless File.exist?(@conf_path)
43
-
44
- yaml_str = File.open(@conf_path, "r") { |f| f.read }
45
- @conf = YAML.load(yaml_str)
42
+ @conf[:path] = default_conf_path
46
43
  end
44
+
45
+ values =
46
+ if FileTest.exist?(@conf[:path])
47
+ yaml_str = File.open(@conf[:path], "r") { |f| f.read }
48
+ YAML.load(yaml_str)
49
+ else
50
+ DEFAULT_VALUES
51
+ end
52
+ @conf.merge!(values)
53
+ @conf[:config_home] = config_home
47
54
  end
48
55
 
49
56
  def_delegators(:@conf,
@@ -91,7 +98,7 @@ module Rbnotes
91
98
  :test => "_test",
92
99
  }
93
100
 
94
- def base_path
101
+ def config_home
95
102
  path = nil
96
103
  xdg, user = ["XDG_CONFIG_HOME", "HOME"].map{|n| ENV[n]}
97
104
  if xdg
@@ -99,15 +106,11 @@ module Rbnotes
99
106
  else
100
107
  path = File.join(user, DIRNAME_COMMON_CONF, DIRNAME_RBNOTES)
101
108
  end
102
- return path
103
- end
104
-
105
- def default_conf_file
106
- File.join(base_path, FILENAME_CONF)
109
+ path
107
110
  end
108
111
 
109
- def use_default_values?
110
- @conf_path.nil? && !File.exist?(default_conf_file)
112
+ def default_conf_path
113
+ File.join(config_home, FILENAME_CONF)
111
114
  end
112
115
 
113
116
  # :startdoc:
@@ -7,13 +7,15 @@ module Rbnotes
7
7
  # :stopdoc:
8
8
 
9
9
  module ErrMsg
10
- MISSING_ARGUMENT = "Missing argument: %s"
11
- MISSING_TIMESTAMP = "Missing timestamp: %s"
12
- NO_EDITOR = "No editor is available: %s"
13
- PROGRAM_ABORT = "External program was aborted: %s"
14
- UNKNOWN_KEYWORD = "Unknown keyword: %s"
15
- INVALID_TIMESTAMP_PATTERN = "Invalid timestamp pattern: %s"
16
- NO_CONF_FILE = "No configuration file: %s"
10
+ MISSING_ARGUMENT = "missing argument: %s"
11
+ MISSING_TIMESTAMP = "missing timestamp: %s"
12
+ NO_EDITOR = "no editor is available: %s"
13
+ PROGRAM_ABORT = "external program was aborted: %s"
14
+ UNKNOWN_KEYWORD = "unknown keyword: %s"
15
+ INVALID_TIMESTAMP_PATTERN = "invalid timestamp pattern: %s"
16
+ NO_CONF_FILE = "no configuration file: %s"
17
+ NO_TEMPLATE_FILE = "no template file: %s"
18
+ INVALID_TIMESTAMP_PATTERN_AS_DATE = "invalid timestamp pattern as date: %s"
17
19
  end
18
20
 
19
21
  # :startdoc:
@@ -86,4 +88,32 @@ module Rbnotes
86
88
  end
87
89
  end
88
90
 
91
+ ##
92
+ # An error raised when no arguments is spcified.
93
+
94
+ class NoArgumentError < Error
95
+ def initialize
96
+ super
97
+ end
98
+ end
99
+
100
+ ##
101
+ # An error raised when the specified template files does not exist.
102
+ #
103
+ class NoTemplateFileError < Error
104
+ def initialize(filepath)
105
+ super(ErrMsg::NO_TEMPLATE_FILE % filepath)
106
+ end
107
+ end
108
+
109
+ ##
110
+ # An error raised when the specified pattern cannot be converted
111
+ # into a date.
112
+ #
113
+ class InvalidTimestampPatternAsDateError < Error
114
+ def initialize(pattern)
115
+ super(ErrMsg::INVALID_TIMESTAMP_PATTERN_AS_DATE % pattern)
116
+ end
117
+ end
118
+
89
119
  end
@@ -99,6 +99,7 @@ module Rbnotes
99
99
 
100
100
  def read_timestamp(args)
101
101
  str = args.shift || read_arg($stdin)
102
+ raise NoArgumentError if str.nil?
102
103
  Textrepo::Timestamp.parse_s(str)
103
104
  end
104
105
 
@@ -112,6 +113,7 @@ module Rbnotes
112
113
 
113
114
  def read_multiple_timestamps(args)
114
115
  strings = args.size < 1 ? read_multiple_args($stdin) : args
116
+ raise NoArgumentError if (strings.nil? || strings.empty?)
115
117
  strings.map { |str| Textrepo::Timestamp.parse_s(str) }
116
118
  end
117
119
 
@@ -136,6 +138,8 @@ module Rbnotes
136
138
  # - "yeasterday" (or "ye")
137
139
  # - "this_week" (or "tw")
138
140
  # - "last_week" (or "lw")
141
+ # - "this_month" (or "tm")
142
+ # - "last_month" (or "lm")
139
143
  #
140
144
  # :call-seq:
141
145
  # expand_keyword_in_args(Array of Strings) -> Array of Strings
@@ -147,7 +151,8 @@ module Rbnotes
147
151
  while args.size > 0
148
152
  arg = args.shift
149
153
  if ["today", "to", "yesterday", "ye",
150
- "this_week", "tw", "last_week", "lw"].include?(arg)
154
+ "this_week", "tw", "last_week", "lw",
155
+ "this_month", "tm", "last_month", "lm"].include?(arg)
151
156
  patterns.concat(Rbnotes.utils.expand_keyword(arg))
152
157
  else
153
158
  patterns << arg
@@ -173,6 +178,10 @@ module Rbnotes
173
178
  patterns.concat(dates_in_this_week.map { |d| timestamp_pattern(d) })
174
179
  when "last_week", "lw"
175
180
  patterns.concat(dates_in_last_week.map { |d| timestamp_pattern(d) })
181
+ when "this_month", "tm"
182
+ patterns.concat(dates_in_this_month.map { |d| timestamp_pattern(d) })
183
+ when "last_month", "lm"
184
+ patterns.concat(dates_in_last_month.map { |d| timestamp_pattern(d) })
176
185
  else
177
186
  raise UnknownKeywordError, keyword
178
187
  end
@@ -183,25 +192,28 @@ module Rbnotes
183
192
  # Makes a headline with the timestamp and subject of the notes, it
184
193
  # looks like as follows:
185
194
  #
186
- # |<------------------ console column size ------------------->|
187
- # +-- timestamp ---+ +- subject (the 1st line of each note) -+
188
- # | | | |
189
- # 20101010001000_123: I love Macintosh. [EOL]
190
- # 20100909090909_999: This is very very long long loooong subje[EOL]
191
- # ++
192
- # ^--- delimiter (2 characters)
195
+ # |<--------------- console column size -------------------->|
196
+ # | |+-- timestamp ---+ +-subject (the 1st line of note) -+
197
+ # | | | |
198
+ # | |20101010001000_123: I love Macintosh. [EOL]
199
+ # | |20100909090909_999: This is very very long looong subj[EOL]
200
+ # |<->| | |
201
+ # ^--- pad ++
202
+ # ^--- delimiter (2 characters)
193
203
  #
194
204
  # The subject part will truncate when it is long.
195
205
 
196
- def make_headline(timestamp, text)
206
+ def make_headline(timestamp, text, pad = nil)
197
207
  _, column = IO.console_size
198
208
  delimiter = ": "
199
209
  timestamp_width = timestamp.to_s.size
200
210
  subject_width = column - timestamp_width - delimiter.size - 1
211
+ subject_width -= pad.size unless pad.nil?
201
212
 
202
213
  subject = remove_heading_markup(text[0])
203
214
 
204
215
  ts_part = "#{timestamp.to_s} "[0..(timestamp_width - 1)]
216
+ ts_part.prepend(pad) unless pad.nil?
205
217
  sj_part = truncate_str(subject, subject_width)
206
218
 
207
219
  ts_part + delimiter + sj_part
@@ -210,6 +222,7 @@ module Rbnotes
210
222
  ##
211
223
  # Finds all notes those timestamps match to given patterns in the
212
224
  # given repository. Returns an Array contains Timestamp objects.
225
+ # The returned Array is sorted by Timestamp.
213
226
  #
214
227
  # :call-seq:
215
228
  # find_notes(Array of timestamp patterns, Textrepo::Repository)
@@ -329,6 +342,36 @@ module Rbnotes
329
342
  dates
330
343
  end
331
344
 
345
+ def dates_in_this_month
346
+ today = Time.now
347
+ first_date = date(Time.new(today.year, today.mon, 1))
348
+ dates_in_month(first_date)
349
+ end
350
+
351
+ def dates_in_last_month
352
+ today = Time.now
353
+ first_date_of_this_month = date(Time.new(today.year, today.mon, 1))
354
+ dates_in_month(first_date_of_this_month.prev_month)
355
+ end
356
+
357
+ def dates_in_month(first_date)
358
+ days = days_in_month(first_date.mon, leap: first_date.leap?)
359
+ dates = [first_date]
360
+ 1.upto(days - 1) { |i| dates << first_date.next_day(i) }
361
+ dates
362
+ end
363
+
364
+ DAYS = {
365
+ # 1 2 3 4 5 6 7 8 9 10 11 12
366
+ # Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
367
+ false => [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
368
+ true => [0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
369
+ }
370
+
371
+ def days_in_month(mon, leap: false)
372
+ DAYS[leap][mon]
373
+ end
374
+
332
375
  def truncate_str(str, size)
333
376
  count = 0
334
377
  result = ""
@@ -1,4 +1,4 @@
1
1
  module Rbnotes
2
- VERSION = "0.4.11"
3
- RELEASE = "2020-12-07"
2
+ VERSION = "0.4.12"
3
+ RELEASE = "2020-12-18"
4
4
  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.11
4
+ version: 0.4.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - mnbi
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-12-07 00:00:00.000000000 Z
11
+ date: 2020-12-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: textrepo
@@ -58,6 +58,9 @@ files:
58
58
  - bin/setup
59
59
  - conf/config.yml
60
60
  - conf/config_deve.yml
61
+ - conf/config_deve_fzf_no_opts.yml
62
+ - conf/config_deve_no_picker.yml
63
+ - conf/config_deve_peco.yml
61
64
  - conf/config_test.yml
62
65
  - etc/zsh/_rbnotes
63
66
  - exe/rbnotes