rbnotes 0.4.7 → 0.4.12
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 +41 -1
- data/Gemfile.lock +2 -2
- 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 +11 -1
- data/lib/rbnotes.rb +1 -0
- data/lib/rbnotes/commands.rb +5 -3
- data/lib/rbnotes/commands/add.rb +26 -1
- data/lib/rbnotes/commands/commands.rb +121 -0
- data/lib/rbnotes/commands/help.rb +1 -38
- data/lib/rbnotes/commands/import.rb +26 -5
- data/lib/rbnotes/commands/list.rb +93 -10
- data/lib/rbnotes/commands/pick.rb +5 -1
- data/lib/rbnotes/commands/search.rb +5 -1
- data/lib/rbnotes/commands/show.rb +60 -15
- data/lib/rbnotes/commands/statistics.rb +55 -0
- data/lib/rbnotes/commands/update.rb +1 -1
- data/lib/rbnotes/conf.rb +25 -11
- data/lib/rbnotes/error.rb +55 -3
- data/lib/rbnotes/statistics.rb +101 -0
- data/lib/rbnotes/utils.rb +111 -25
- data/lib/rbnotes/version.rb +2 -2
- metadata +9 -2
@@ -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,29 @@ module Rbnotes::Commands
|
|
25
28
|
# execute([PATHNAME], Rbnotes::Conf or Hash) -> nil
|
26
29
|
|
27
30
|
def execute(args, conf)
|
31
|
+
@opts = {}
|
32
|
+
while args.size > 0
|
33
|
+
arg = args.shift
|
34
|
+
case arg
|
35
|
+
when "-m", "--use-mtime"
|
36
|
+
@opts[:use_mtime] = true
|
37
|
+
else
|
38
|
+
args.unshift(arg)
|
39
|
+
break
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
28
43
|
file = args.shift
|
29
44
|
unless file.nil?
|
30
45
|
st = File::Stat.new(file)
|
31
|
-
|
32
|
-
|
46
|
+
time = nil
|
47
|
+
if @opts[:use_mtime]
|
48
|
+
time = st.mtime
|
49
|
+
else
|
50
|
+
time = st.respond_to?(:birthtime) ? st.birthtime : st.mtime
|
51
|
+
end
|
52
|
+
|
53
|
+
stamp = Textrepo::Timestamp.new(time)
|
33
54
|
puts "Import [%s] (timestamp [%s]) ..." % [file, stamp]
|
34
55
|
|
35
56
|
repo = Textrepo.init(conf)
|
@@ -72,7 +93,7 @@ module Rbnotes::Commands
|
|
72
93
|
puts "Cannot create a text into the repository with the" \
|
73
94
|
" specified file [%s]." % file
|
74
95
|
puts "For, the birthtime [%s] is identical to some notes" \
|
75
|
-
" already exists in the reopsitory." %
|
96
|
+
" already exists in the reopsitory." % time
|
76
97
|
puts "Change the birthtime of the target file, then retry."
|
77
98
|
else
|
78
99
|
puts "... Done."
|
@@ -86,7 +107,7 @@ module Rbnotes::Commands
|
|
86
107
|
def help # :nodoc:
|
87
108
|
puts <<HELP
|
88
109
|
usage:
|
89
|
-
#{Rbnotes::NAME} import FILE
|
110
|
+
#{Rbnotes::NAME} import [-m|--use-mtime] FILE
|
90
111
|
|
91
112
|
Imports a existing file which specified by the argument as a note.
|
92
113
|
|
@@ -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
|
#
|
@@ -51,18 +53,68 @@ module Rbnotes::Commands
|
|
51
53
|
# execute(Array, Rbnotes::Conf or Hash) -> nil
|
52
54
|
|
53
55
|
def execute(args, conf)
|
54
|
-
|
56
|
+
@opts = {}
|
57
|
+
while args.size > 0
|
58
|
+
arg = args.shift
|
59
|
+
case arg
|
60
|
+
when "-w", "--week"
|
61
|
+
@opts[:enum_week] = true
|
62
|
+
when "-v", "--verbose"
|
63
|
+
@opts[:verbose] = true
|
64
|
+
else
|
65
|
+
args.unshift(arg)
|
66
|
+
break
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
patterns = nil
|
71
|
+
if @opts[:enum_week]
|
72
|
+
arg = args.shift || Textrepo::Timestamp.now[0, 8]
|
73
|
+
case arg.size
|
74
|
+
when "yyyymodd".size, "yyyymoddhhmiss".size, "yyyymoddhhmiss_sfx".size
|
75
|
+
stamp_str = "#{arg}000000"[0, 14]
|
76
|
+
timestamp = Textrepo::Timestamp.parse_s(stamp_str)
|
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
|
85
|
+
else
|
86
|
+
raise InvalidTimestampPatternAsDateError, args.unshift(arg)
|
87
|
+
end
|
88
|
+
patterns = Rbnotes.utils.timestamp_patterns_in_week(timestamp)
|
89
|
+
else
|
90
|
+
patterns = Rbnotes.utils.expand_keyword_in_args(args)
|
91
|
+
end
|
92
|
+
|
55
93
|
@repo = Textrepo.init(conf)
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
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
|
60
112
|
end
|
61
113
|
|
62
114
|
def help # :nodoc:
|
63
115
|
puts <<HELP
|
64
116
|
usage:
|
65
|
-
#{Rbnotes::NAME} list [STAMP_PATTERN|KEYWORD]
|
117
|
+
#{Rbnotes::NAME} list [-w|--week][STAMP_PATTERN|KEYWORD]
|
66
118
|
|
67
119
|
Show a list of notes. When no arguments, make a list with all notes
|
68
120
|
in the repository. When specified STAMP_PATTERN, only those match the
|
@@ -83,9 +135,40 @@ KEYWORD:
|
|
83
135
|
- "yeasterday" (or "ye")
|
84
136
|
- "this_week" (or "tw")
|
85
137
|
- "last_week" (or "lw")
|
138
|
+
- "this_month" (or "tm")
|
139
|
+
- "last_month" (or "lm")
|
86
140
|
|
141
|
+
An option "--week" is also acceptable. It specifies to enumerate all
|
142
|
+
days of a week. Typically, the option is used with a STAMP_PATTERN
|
143
|
+
which specifies a date, such "20201117", then it enumerates all days
|
144
|
+
of the week which contains "17th November 2020".
|
145
|
+
|
146
|
+
A STAMP_PATTERN other than (a) and (b) causes an error if it was used
|
147
|
+
with "--week" option.
|
148
|
+
|
149
|
+
When no STAMP_PATTERN was specified with "--week" option, the output
|
150
|
+
would be as same as the KEYWORD, "this_week" was specified.
|
87
151
|
HELP
|
88
152
|
end
|
89
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
|
+
|
90
173
|
end
|
91
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(
|
28
|
+
result = Open3.pipeline_rw(cmds) { |stdin, stdout, _|
|
25
29
|
stdin.puts list
|
26
30
|
stdin.close
|
27
31
|
stdout.read
|
@@ -77,11 +77,15 @@ HELP
|
|
77
77
|
def timestamp_size
|
78
78
|
timestamp.to_s.size
|
79
79
|
end
|
80
|
+
|
81
|
+
def line_number_digits_size
|
82
|
+
line_number.to_s.size
|
83
|
+
end
|
80
84
|
}
|
81
85
|
|
82
86
|
def print_search_result(entries)
|
83
87
|
maxcol_stamp = entries.map(&:timestamp_size).max
|
84
|
-
maxcol_num = entries.map(&:
|
88
|
+
maxcol_num = entries.map(&:line_number_digits_size).max
|
85
89
|
|
86
90
|
sort(entries).each { |e|
|
87
91
|
stamp_display = "%- *s" % [maxcol_stamp, e.timestamp]
|
@@ -1,52 +1,97 @@
|
|
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
|
-
# A string for Timestamp must be:
|
8
|
+
# A string for Textrepo::Timestamp must be:
|
9
9
|
#
|
10
10
|
# "20201106112600" : year, date, time and sec
|
11
11
|
# "20201106112600_012" : with suffix
|
12
12
|
#
|
13
|
-
# If no argument is passed, reads the standard input for
|
13
|
+
# If no argument is passed, reads the standard input for arguments.
|
14
14
|
|
15
15
|
class Show < Command
|
16
16
|
|
17
17
|
def description # :nodoc:
|
18
|
-
"Show the content of
|
18
|
+
"Show the content of notes"
|
19
19
|
end
|
20
20
|
|
21
21
|
def execute(args, conf)
|
22
|
-
|
23
|
-
|
22
|
+
stamps = Rbnotes.utils.read_multiple_timestamps(args)
|
24
23
|
repo = Textrepo.init(conf)
|
25
|
-
|
24
|
+
|
25
|
+
content = stamps.map { |stamp| [stamp, repo.read(stamp)] }.to_h
|
26
26
|
|
27
27
|
pager = conf[:pager]
|
28
28
|
unless pager.nil?
|
29
|
-
|
30
|
-
Open3.pipeline_w(pager) { |stdin|
|
31
|
-
stdin.puts content
|
32
|
-
stdin.close
|
33
|
-
}
|
29
|
+
puts_with_pager(pager, make_output(content))
|
34
30
|
else
|
35
|
-
puts content
|
31
|
+
puts make_output(content)
|
36
32
|
end
|
37
33
|
end
|
38
34
|
|
39
35
|
def help # :nodoc:
|
40
36
|
puts <<HELP
|
41
37
|
usage:
|
42
|
-
#{Rbnotes::NAME} show [TIMESTAMP]
|
38
|
+
#{Rbnotes::NAME} show [TIMESTAMP...]
|
43
39
|
|
44
|
-
Show the content of given
|
40
|
+
Show the content of given notes. TIMESTAMP must be a fully qualified
|
45
41
|
one, such "20201016165130" or "20201016165130_012" if it has a suffix.
|
46
42
|
|
47
43
|
The command try to read its argument from the standard input when no
|
48
44
|
argument was passed in the command line.
|
49
45
|
HELP
|
50
46
|
end
|
47
|
+
|
48
|
+
# :stopdoc:
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def puts_with_pager(pager, output)
|
53
|
+
require "open3"
|
54
|
+
Open3.pipeline_w(pager) { |stdin|
|
55
|
+
stdin.puts output
|
56
|
+
stdin.close
|
57
|
+
}
|
58
|
+
end
|
59
|
+
|
60
|
+
require "io/console/size"
|
61
|
+
|
62
|
+
def make_output(content)
|
63
|
+
if content.size <= 1
|
64
|
+
return content.values[0]
|
65
|
+
end
|
66
|
+
|
67
|
+
_, column = IO.console_size
|
68
|
+
output = content.map { |timestamp, text|
|
69
|
+
ary = [make_heading(timestamp, [column, 72].min)]
|
70
|
+
ary.concat(text)
|
71
|
+
ary
|
72
|
+
}
|
73
|
+
|
74
|
+
output = insert_delimiter(output, "")
|
75
|
+
output.flatten
|
76
|
+
end
|
77
|
+
|
78
|
+
def make_heading(timestamp, column)
|
79
|
+
stamp_str = timestamp.to_s
|
80
|
+
length = column - (stamp_str.size + 2)
|
81
|
+
"#{stamp_str} #{Array.new(length, '-').join}"
|
82
|
+
end
|
83
|
+
|
84
|
+
def insert_delimiter(ary, delimiter = "")
|
85
|
+
result = []
|
86
|
+
ary.each { |e|
|
87
|
+
result << e
|
88
|
+
result << delimiter
|
89
|
+
}
|
90
|
+
result.delete_at(-1)
|
91
|
+
result
|
92
|
+
end
|
93
|
+
|
94
|
+
# :startdoc:
|
95
|
+
|
51
96
|
end
|
52
97
|
end
|
@@ -0,0 +1,55 @@
|
|
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
|
+
report = :total
|
13
|
+
while args.size > 0
|
14
|
+
arg = args.shift
|
15
|
+
case arg
|
16
|
+
when "-y", "--yearly"
|
17
|
+
report = :yearly
|
18
|
+
break
|
19
|
+
when "-m", "--monthly"
|
20
|
+
report = :monthly
|
21
|
+
break
|
22
|
+
else
|
23
|
+
args.unshift(arg)
|
24
|
+
raise ArgumentError, "invalid option or argument: %s" % args.join(" ")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
stats = Rbnotes::Statistics.new(conf)
|
29
|
+
case report
|
30
|
+
when :yearly
|
31
|
+
stats.yearly_report
|
32
|
+
when :monthly
|
33
|
+
stats.monthly_report
|
34
|
+
else
|
35
|
+
stats.total_report
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def help
|
40
|
+
puts <<HELP
|
41
|
+
usage:
|
42
|
+
#{Rbnotes::NAME} statistics ([-y|--yearly]|[-m|--monthly])
|
43
|
+
|
44
|
+
option:
|
45
|
+
-y, --yearly : print yearly report
|
46
|
+
-m, --monthly : print monthly report
|
47
|
+
|
48
|
+
Show statistics.
|
49
|
+
|
50
|
+
In the version #{Rbnotes::VERSION}, only number of notes is supported.
|
51
|
+
HELP
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
data/lib/rbnotes/conf.rb
CHANGED
@@ -31,17 +31,26 @@ module Rbnotes
|
|
31
31
|
|
32
32
|
DIRNAME_COMMON_CONF = ".config"
|
33
33
|
|
34
|
-
def initialize(
|
35
|
-
@conf_path = conf_path || File.join(base_path, FILENAME_CONF)
|
36
|
-
|
34
|
+
def initialize(path = nil) # :nodoc:
|
37
35
|
@conf = {}
|
38
|
-
|
39
|
-
|
40
|
-
|
36
|
+
|
37
|
+
unless path.nil?
|
38
|
+
abspath = File.expand_path(path)
|
39
|
+
raise NoConfFileError, path unless FileTest.exist?(abspath)
|
40
|
+
@conf[:path] = abspath
|
41
41
|
else
|
42
|
-
@conf
|
42
|
+
@conf[:path] = default_conf_path
|
43
43
|
end
|
44
|
-
|
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
|
45
54
|
end
|
46
55
|
|
47
56
|
def_delegators(:@conf,
|
@@ -89,7 +98,7 @@ module Rbnotes
|
|
89
98
|
:test => "_test",
|
90
99
|
}
|
91
100
|
|
92
|
-
def
|
101
|
+
def config_home
|
93
102
|
path = nil
|
94
103
|
xdg, user = ["XDG_CONFIG_HOME", "HOME"].map{|n| ENV[n]}
|
95
104
|
if xdg
|
@@ -97,12 +106,17 @@ module Rbnotes
|
|
97
106
|
else
|
98
107
|
path = File.join(user, DIRNAME_COMMON_CONF, DIRNAME_RBNOTES)
|
99
108
|
end
|
100
|
-
|
109
|
+
path
|
110
|
+
end
|
111
|
+
|
112
|
+
def default_conf_path
|
113
|
+
File.join(config_home, FILENAME_CONF)
|
101
114
|
end
|
102
|
-
end
|
103
115
|
|
104
116
|
# :startdoc:
|
105
117
|
|
118
|
+
end
|
119
|
+
|
106
120
|
class << self
|
107
121
|
##
|
108
122
|
# Gets the instance of Rbnotes::Conf. An optional argument is to
|