rbnotes 0.4.10 → 0.4.15
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/.github/workflows/main.yml +18 -0
- data/.gitignore +0 -1
- data/CHANGELOG.md +45 -1
- data/Gemfile +1 -1
- data/Gemfile.lock +7 -7
- data/README.md +2 -1
- data/Rakefile +1 -1
- data/conf/config.yml +1 -0
- data/conf/config_deve.yml +1 -0
- data/conf/config_deve_fzf_no_opts.yml +8 -0
- data/conf/config_deve_no_picker.yml +7 -0
- data/conf/config_deve_peco.yml +8 -0
- data/etc/zsh/_rbnotes +93 -0
- data/exe/rbnotes +10 -1
- data/lib/rbnotes.rb +1 -5
- data/lib/rbnotes/commands.rb +3 -2
- data/lib/rbnotes/commands/add.rb +45 -14
- data/lib/rbnotes/commands/commands.rb +17 -12
- data/lib/rbnotes/commands/import.rb +37 -5
- data/lib/rbnotes/commands/list.rb +63 -33
- data/lib/rbnotes/commands/pick.rb +33 -4
- data/lib/rbnotes/commands/show.rb +102 -15
- data/lib/rbnotes/commands/statistics.rb +74 -0
- data/lib/rbnotes/commands/update.rb +21 -10
- data/lib/rbnotes/conf.rb +25 -11
- data/lib/rbnotes/error.rb +47 -6
- data/lib/rbnotes/statistics.rb +101 -0
- data/lib/rbnotes/utils.rb +239 -77
- data/lib/rbnotes/version.rb +2 -2
- data/rbnotes.gemspec +1 -1
- metadata +12 -6
- data/.travis.yml +0 -6
@@ -4,9 +4,12 @@ module Rbnotes::Commands
|
|
4
4
|
# Imports a existing file which specified by the argument as a note.
|
5
5
|
#
|
6
6
|
# A timestamp is generated referring to the birthtime of the given
|
7
|
-
# file. If birthtime is not available on the system,
|
7
|
+
# file. If birthtime is not available on the system, uses mtime
|
8
8
|
# (modification time).
|
9
9
|
#
|
10
|
+
# When the option, "-m" (or "--use-mtime") is specified, uses mtime
|
11
|
+
# instead of birthtime.
|
12
|
+
#
|
10
13
|
# Occasionally, there is another note which has the same timestmap
|
11
14
|
# in the repository. Then, tries to create a new timestamp with a
|
12
15
|
# suffix. Unluckily, when such timestamp with a suffix already
|
@@ -25,11 +28,20 @@ module Rbnotes::Commands
|
|
25
28
|
# execute([PATHNAME], Rbnotes::Conf or Hash) -> nil
|
26
29
|
|
27
30
|
def execute(args, conf)
|
31
|
+
@opts = {}
|
32
|
+
parse_opts(args)
|
33
|
+
|
28
34
|
file = args.shift
|
29
35
|
unless file.nil?
|
30
36
|
st = File::Stat.new(file)
|
31
|
-
|
32
|
-
|
37
|
+
time = nil
|
38
|
+
if @opts[:use_mtime]
|
39
|
+
time = st.mtime
|
40
|
+
else
|
41
|
+
time = st.respond_to?(:birthtime) ? st.birthtime : st.mtime
|
42
|
+
end
|
43
|
+
|
44
|
+
stamp = Textrepo::Timestamp.new(time)
|
33
45
|
puts "Import [%s] (timestamp [%s]) ..." % [file, stamp]
|
34
46
|
|
35
47
|
repo = Textrepo.init(conf)
|
@@ -72,7 +84,7 @@ module Rbnotes::Commands
|
|
72
84
|
puts "Cannot create a text into the repository with the" \
|
73
85
|
" specified file [%s]." % file
|
74
86
|
puts "For, the birthtime [%s] is identical to some notes" \
|
75
|
-
" already exists in the reopsitory." %
|
87
|
+
" already exists in the reopsitory." % time
|
76
88
|
puts "Change the birthtime of the target file, then retry."
|
77
89
|
else
|
78
90
|
puts "... Done."
|
@@ -86,7 +98,7 @@ module Rbnotes::Commands
|
|
86
98
|
def help # :nodoc:
|
87
99
|
puts <<HELP
|
88
100
|
usage:
|
89
|
-
#{Rbnotes::NAME} import FILE
|
101
|
+
#{Rbnotes::NAME} import [-m|--use-mtime] FILE
|
90
102
|
|
91
103
|
Imports a existing file which specified by the argument as a note.
|
92
104
|
|
@@ -95,5 +107,25 @@ If birthtime is not available on the system, use mtime (modification
|
|
95
107
|
time).
|
96
108
|
HELP
|
97
109
|
end
|
110
|
+
|
111
|
+
# :stopdoc:
|
112
|
+
|
113
|
+
private
|
114
|
+
|
115
|
+
def parse_opts(args)
|
116
|
+
while args.size > 0
|
117
|
+
arg = args.shift
|
118
|
+
case arg
|
119
|
+
when "-m", "--use-mtime"
|
120
|
+
@opts[:use_mtime] = true
|
121
|
+
else
|
122
|
+
args.unshift(arg)
|
123
|
+
break
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
# :startdoc:
|
129
|
+
|
98
130
|
end
|
99
131
|
end
|
@@ -24,10 +24,12 @@ module Rbnotes::Commands
|
|
24
24
|
#
|
25
25
|
# A keyword must be one of them:
|
26
26
|
#
|
27
|
-
#
|
28
|
-
#
|
29
|
-
#
|
30
|
-
#
|
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
|
#
|
@@ -52,38 +54,30 @@ module Rbnotes::Commands
|
|
52
54
|
|
53
55
|
def execute(args, conf)
|
54
56
|
@opts = {}
|
55
|
-
|
56
|
-
arg = args.shift
|
57
|
-
case arg
|
58
|
-
when "-w", "--week"
|
59
|
-
@opts[:enum_week] = true
|
60
|
-
else
|
61
|
-
args.unshift(arg)
|
62
|
-
break
|
63
|
-
end
|
64
|
-
end
|
57
|
+
parse_opts(args)
|
65
58
|
|
66
|
-
|
67
|
-
|
68
|
-
arg = args.shift || Textrepo::Timestamp.now[0, 8]
|
69
|
-
case arg.size
|
70
|
-
when "yyyymodd".size, "yyyymoddhhmiss".size, "yyyymoddhhmiss_sfx".size
|
71
|
-
stamp_str = "#{arg}000000"[0, 14]
|
72
|
-
timestamp = Textrepo::Timestamp.parse_s(stamp_str)
|
73
|
-
patterns = Rbnotes.utils.timestamp_patterns_in_week(timestamp)
|
74
|
-
else
|
75
|
-
raise InvalidTimestampPatternError,
|
76
|
-
"cannot convert to a date [%s]" % args.unshift(arg)
|
77
|
-
end
|
78
|
-
else
|
79
|
-
patterns = Rbnotes.utils.expand_keyword_in_args(args)
|
80
|
-
end
|
59
|
+
utils = Rbnotes.utils
|
60
|
+
patterns = utils.read_timestamp_patterns(args, enum_week: @opts[:enum_week])
|
81
61
|
|
82
62
|
@repo = Textrepo.init(conf)
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
63
|
+
notes = utils.find_notes(patterns, @repo)
|
64
|
+
output = []
|
65
|
+
if @opts[:verbose]
|
66
|
+
collect_timestamps_by_date(notes).each { |date, timestamps|
|
67
|
+
output << "#{date} (#{timestamps.size})"
|
68
|
+
timestamps.each { |timestamp|
|
69
|
+
pad = " "
|
70
|
+
output << utils.make_headline(timestamp,
|
71
|
+
@repo.read(timestamp), pad)
|
72
|
+
}
|
73
|
+
}
|
74
|
+
else
|
75
|
+
notes.each { |timestamp|
|
76
|
+
output << utils.make_headline(timestamp,
|
77
|
+
@repo.read(timestamp))
|
78
|
+
}
|
79
|
+
end
|
80
|
+
puts output
|
87
81
|
end
|
88
82
|
|
89
83
|
def help # :nodoc:
|
@@ -110,6 +104,8 @@ KEYWORD:
|
|
110
104
|
- "yeasterday" (or "ye")
|
111
105
|
- "this_week" (or "tw")
|
112
106
|
- "last_week" (or "lw")
|
107
|
+
- "this_month" (or "tm")
|
108
|
+
- "last_month" (or "lm")
|
113
109
|
|
114
110
|
An option "--week" is also acceptable. It specifies to enumerate all
|
115
111
|
days of a week. Typically, the option is used with a STAMP_PATTERN
|
@@ -124,5 +120,39 @@ would be as same as the KEYWORD, "this_week" was specified.
|
|
124
120
|
HELP
|
125
121
|
end
|
126
122
|
|
123
|
+
# :stopdoc:
|
124
|
+
|
125
|
+
private
|
126
|
+
|
127
|
+
def parse_opts(args)
|
128
|
+
while args.size > 0
|
129
|
+
arg = args.shift
|
130
|
+
case arg
|
131
|
+
when "-w", "--week"
|
132
|
+
@opts[:enum_week] = true
|
133
|
+
when "-v", "--verbose"
|
134
|
+
@opts[:verbose] = true
|
135
|
+
else
|
136
|
+
args.unshift(arg)
|
137
|
+
break
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def collect_timestamps_by_date(timestamps)
|
143
|
+
result = {}
|
144
|
+
timestamps.map { |ts|
|
145
|
+
[ts.strftime("%Y-%m-%d"), ts]
|
146
|
+
}.reduce(result) { |r, pair|
|
147
|
+
date, stamp = pair
|
148
|
+
r[date] ||= []
|
149
|
+
r[date] << stamp
|
150
|
+
r
|
151
|
+
}
|
152
|
+
result
|
153
|
+
end
|
154
|
+
|
155
|
+
# :startdoc:
|
156
|
+
|
127
157
|
end
|
128
158
|
end
|
@@ -10,18 +10,27 @@ module Rbnotes::Commands
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def execute(args, conf)
|
13
|
-
|
13
|
+
@opts = {}
|
14
|
+
parse_opts(args)
|
15
|
+
|
16
|
+
utils = Rbnotes.utils
|
17
|
+
patterns = utils.read_timestamp_patterns(args, enum_week: @opts[:enum_week])
|
18
|
+
|
14
19
|
@repo = Textrepo.init(conf)
|
15
20
|
|
16
21
|
list = []
|
17
|
-
|
18
|
-
list <<
|
22
|
+
utils.find_notes(patterns, @repo).each { |timestamp|
|
23
|
+
list << utils.make_headline(timestamp, @repo.read(timestamp))
|
19
24
|
}
|
20
25
|
|
21
26
|
picker = conf[:picker]
|
22
27
|
unless picker.nil?
|
28
|
+
picker_opts = conf[:picker_option]
|
29
|
+
cmds = [picker]
|
30
|
+
cmds.concat(picker_opts.split) unless picker_opts.nil?
|
31
|
+
|
23
32
|
require 'open3'
|
24
|
-
result = Open3.pipeline_rw(
|
33
|
+
result = Open3.pipeline_rw(cmds) { |stdin, stdout, _|
|
25
34
|
stdin.puts list
|
26
35
|
stdin.close
|
27
36
|
stdout.read
|
@@ -43,5 +52,25 @@ is specified, it will behave as same as "list" command.
|
|
43
52
|
|
44
53
|
HELP
|
45
54
|
end
|
55
|
+
|
56
|
+
# :stopdoc:
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def parse_opts(args)
|
61
|
+
while args.size > 0
|
62
|
+
arg = args.shift
|
63
|
+
case arg
|
64
|
+
when "-w", "--week"
|
65
|
+
@opts[:enum_week] = true
|
66
|
+
else
|
67
|
+
args.unshift(arg)
|
68
|
+
break
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# :startdoc:
|
74
|
+
|
46
75
|
end
|
47
76
|
end
|
@@ -1,52 +1,139 @@
|
|
1
1
|
module Rbnotes::Commands
|
2
2
|
|
3
3
|
##
|
4
|
-
# Shows the content of the
|
4
|
+
# Shows the content of the notes specified by arguments. Each
|
5
5
|
# argument must be a string which can be converted into
|
6
6
|
# Textrepo::Timestamp object.
|
7
7
|
#
|
8
|
-
#
|
8
|
+
# Accepts an option with `-n NUMBER` (or `--num-of-lines`), to show
|
9
|
+
# the first NUMBER lines of the content of each note.
|
10
|
+
#
|
11
|
+
# A string for Textrepo::Timestamp must be:
|
9
12
|
#
|
10
13
|
# "20201106112600" : year, date, time and sec
|
11
14
|
# "20201106112600_012" : with suffix
|
12
15
|
#
|
13
|
-
# If no argument is passed, reads the standard input for
|
14
|
-
|
16
|
+
# If no argument is passed, reads the standard input for arguments.
|
17
|
+
# If a specified timestamp does not exist in the repository as a key,
|
18
|
+
# Rbnotes::MissingTimestampError will occur.
|
15
19
|
class Show < Command
|
16
20
|
|
17
21
|
def description # :nodoc:
|
18
|
-
"Show the content of
|
22
|
+
"Show the content of notes"
|
19
23
|
end
|
20
24
|
|
21
25
|
def execute(args, conf)
|
22
|
-
|
26
|
+
@opts = {}
|
27
|
+
parse_opts(args)
|
23
28
|
|
29
|
+
stamps = Rbnotes.utils.read_multiple_timestamps(args)
|
24
30
|
repo = Textrepo.init(conf)
|
25
|
-
|
31
|
+
|
32
|
+
content = stamps.map { |stamp|
|
33
|
+
begin
|
34
|
+
text = repo.read(stamp)
|
35
|
+
rescue Textrepo::MissingTimestampError => _
|
36
|
+
raise Rbnotes::MissingTimestampError, stamp
|
37
|
+
end
|
38
|
+
|
39
|
+
lines = text.size
|
40
|
+
if @opts[:num_of_lines].to_i > 0
|
41
|
+
lines = [@opts[:num_of_lines], lines].min
|
42
|
+
end
|
43
|
+
|
44
|
+
[stamp, text[0, lines]]
|
45
|
+
}.to_h
|
26
46
|
|
27
47
|
pager = conf[:pager]
|
28
48
|
unless pager.nil?
|
29
|
-
|
30
|
-
Open3.pipeline_w(pager) { |stdin|
|
31
|
-
stdin.puts content
|
32
|
-
stdin.close
|
33
|
-
}
|
49
|
+
puts_with_pager(pager, make_output(content))
|
34
50
|
else
|
35
|
-
puts content
|
51
|
+
puts make_output(content)
|
36
52
|
end
|
37
53
|
end
|
38
54
|
|
39
55
|
def help # :nodoc:
|
40
56
|
puts <<HELP
|
41
57
|
usage:
|
42
|
-
#{Rbnotes::NAME} show [TIMESTAMP]
|
58
|
+
#{Rbnotes::NAME} show [(-n|--num-of-lines) NUMBER] [TIMESTAMP...]
|
43
59
|
|
44
|
-
Show the content of given
|
60
|
+
Show the content of given notes. TIMESTAMP must be a fully qualified
|
45
61
|
one, such "20201016165130" or "20201016165130_012" if it has a suffix.
|
46
62
|
|
63
|
+
Accept an option with `-n NUMBER` (or `--num-of-lines`), to show the
|
64
|
+
first NUMBER lines of the content of each note.
|
65
|
+
|
47
66
|
The command try to read its argument from the standard input when no
|
48
67
|
argument was passed in the command line.
|
49
68
|
HELP
|
50
69
|
end
|
70
|
+
|
71
|
+
# :stopdoc:
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
def parse_opts(args)
|
76
|
+
while args.size > 0
|
77
|
+
arg = args.shift
|
78
|
+
case arg
|
79
|
+
when "-n", "--num-of-lines"
|
80
|
+
num_of_lines = args.shift
|
81
|
+
raise ArgumentError, "missing number: %s" % args.unshift(arg) if num_of_lines.nil?
|
82
|
+
|
83
|
+
num_of_lines = num_of_lines.to_i
|
84
|
+
raise ArgumentError, "illegal number (must be greater than 0): %d" % num_of_lines unless num_of_lines > 0
|
85
|
+
|
86
|
+
@opts[:num_of_lines] = num_of_lines
|
87
|
+
else
|
88
|
+
args.unshift(arg)
|
89
|
+
break
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def puts_with_pager(pager, output)
|
95
|
+
require "open3"
|
96
|
+
Open3.pipeline_w(pager) { |stdin|
|
97
|
+
stdin.puts output
|
98
|
+
stdin.close
|
99
|
+
}
|
100
|
+
end
|
101
|
+
|
102
|
+
require "io/console/size"
|
103
|
+
|
104
|
+
def make_output(content)
|
105
|
+
if content.size <= 1
|
106
|
+
return content.values[0]
|
107
|
+
end
|
108
|
+
|
109
|
+
_, column = IO.console_size
|
110
|
+
output = content.map { |timestamp, text|
|
111
|
+
ary = [make_heading(timestamp, [column, 72].min)]
|
112
|
+
ary.concat(text)
|
113
|
+
ary
|
114
|
+
}
|
115
|
+
|
116
|
+
output = insert_delimiter(output, "")
|
117
|
+
output.flatten
|
118
|
+
end
|
119
|
+
|
120
|
+
def make_heading(timestamp, column)
|
121
|
+
stamp_str = timestamp.to_s
|
122
|
+
length = column - (stamp_str.size + 2)
|
123
|
+
"#{stamp_str} #{Array.new(length, '-').join}"
|
124
|
+
end
|
125
|
+
|
126
|
+
def insert_delimiter(ary, delimiter = "")
|
127
|
+
result = []
|
128
|
+
ary.each { |e|
|
129
|
+
result << e
|
130
|
+
result << delimiter
|
131
|
+
}
|
132
|
+
result.delete_at(-1)
|
133
|
+
result
|
134
|
+
end
|
135
|
+
|
136
|
+
# :startdoc:
|
137
|
+
|
51
138
|
end
|
52
139
|
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module Rbnotes::Commands
|
2
|
+
##
|
3
|
+
# Shows statistics.
|
4
|
+
|
5
|
+
class Statistics < Command
|
6
|
+
|
7
|
+
def description # :nodoc:
|
8
|
+
"Show statistics values"
|
9
|
+
end
|
10
|
+
|
11
|
+
def execute(args, conf)
|
12
|
+
@opts = {}
|
13
|
+
parse_opts(args)
|
14
|
+
|
15
|
+
report = :total
|
16
|
+
if @opts[:yearly]
|
17
|
+
report = :yearly
|
18
|
+
elsif @opts[:monthly]
|
19
|
+
report = :monthly
|
20
|
+
end
|
21
|
+
|
22
|
+
stats = Rbnotes::Statistics.new(conf)
|
23
|
+
case report
|
24
|
+
when :yearly
|
25
|
+
stats.yearly_report
|
26
|
+
when :monthly
|
27
|
+
stats.monthly_report
|
28
|
+
else
|
29
|
+
stats.total_report
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def help
|
34
|
+
puts <<HELP
|
35
|
+
usage:
|
36
|
+
#{Rbnotes::NAME} statistics ([-y|--yearly]|[-m|--monthly])
|
37
|
+
|
38
|
+
option:
|
39
|
+
-y, --yearly : print yearly report
|
40
|
+
-m, --monthly : print monthly report
|
41
|
+
|
42
|
+
Show statistics.
|
43
|
+
|
44
|
+
In the version #{Rbnotes::VERSION}, only number of notes is supported.
|
45
|
+
HELP
|
46
|
+
end
|
47
|
+
|
48
|
+
# :stopdoc:
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def parse_opts(args)
|
53
|
+
while args.size > 0
|
54
|
+
arg = args.shift
|
55
|
+
case arg
|
56
|
+
when "-y", "--yearly"
|
57
|
+
@opts[:yearly] = true
|
58
|
+
@opts[:monthly] = false
|
59
|
+
break
|
60
|
+
when "-m", "--monthly"
|
61
|
+
@opts[:yearly] = false
|
62
|
+
@opts[:monthly] = true
|
63
|
+
break
|
64
|
+
else
|
65
|
+
args.unshift(arg)
|
66
|
+
raise ArgumentError, "invalid option or argument: %s" % args.join(" ")
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# :startdoc:
|
72
|
+
|
73
|
+
end
|
74
|
+
end
|