noteman 0.0.0 → 0.1.0

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
  SHA1:
3
- metadata.gz: cfef1b0d08554efc0f7bfc71f6ed9b543e7c2cbf
4
- data.tar.gz: 6fc35f393c65667903582ec4f3a6a55a6dec6481
3
+ metadata.gz: e598f1a385a1bd21e540785be4bc5475a822c1fb
4
+ data.tar.gz: 7cd126062f9066f2e331f012a661977add8d4d00
5
5
  SHA512:
6
- metadata.gz: cd280e064149e5bd7fe56a8d12a55acb8f880c31b085ff3ffb54234a64e29370ba153039038dab455c901c86d9a1482a6b3f658c950d15c466b25b76d86136df
7
- data.tar.gz: 0764f98f71f87d9c03e506cb8d40deb9ea314f133c8c3445906756697fe65184baf15fefec6e4308827c554455acd6b145454f92621a67707bbfc536aa89b500
6
+ metadata.gz: 74a734a10396b3a61e4ebd9920c16552ab48a9677ccae927d3da5bd5abc39c0fe1193f57180d20464df32aeaea61b4a1ae8493810f200171b5c741ea19f383fc
7
+ data.tar.gz: 26643fb89305db7cb9764d5271d57a725edb33ed47695516ea38ff43cb977fed1087a560e4f782b1fcacc7477b4bb8d9e6df638d5e8230193a61bbbb09859326
data/README.md ADDED
@@ -0,0 +1,12 @@
1
+ Noteman
2
+ ===
3
+
4
+ You advanced note manager.
5
+
6
+ Still in development.
7
+
8
+ ## Get started with the code
9
+
10
+ ```bash
11
+ bundle install
12
+ ```
data/bin/note CHANGED
@@ -1,7 +1,80 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
+ require 'gli'
3
4
  require 'noteman'
4
5
 
5
- inbox = Inbox.new
6
+ include GLI::App
7
+ include Noteman::Display
6
8
 
7
- inbox.hi
9
+ program_desc 'A CLI note manager.'
10
+
11
+ desc 'Do the action to all resulting notes.'
12
+ switch [:a, :all]
13
+
14
+ default_command :find
15
+
16
+ desc 'Search for notes.'
17
+ arg_name 'keywords'
18
+ command :find do |c|
19
+ c.desc 'Search by fomula.'
20
+ c.flag [:f, :fomula]
21
+
22
+ c.action do |global_options,options,args|
23
+ nm = Noteman::NoteManager.search
24
+ if options[:fomula]
25
+ nm.search_by_fomular options[:fomula].result
26
+ end
27
+
28
+ if args.length > 0
29
+ tags = []
30
+ keywords = []
31
+ args.each do |arg|
32
+ if arg.start_with? '@'
33
+ tags << arg.tr('@', '')
34
+ else
35
+ keywords << arg
36
+ end
37
+ end
38
+ nm.by_tags tags
39
+ nm.by_keywords keywords
40
+ nm.result.each { |n| puts n.file }
41
+ else
42
+ note = Noteman::Finder.new.find_note
43
+ note.view
44
+ end
45
+ end
46
+ end
47
+
48
+ desc 'List all tags.'
49
+ command :tags do |c|
50
+ c.desc 'List results one per line, to assist with shell completion.'
51
+ c.switch [:c]
52
+
53
+ c.action do |global_options,options,args|
54
+ nm = Noteman::NoteManager.search
55
+ if options[:c]
56
+ nm.tags.keys.each { |tag| puts tag }
57
+ else
58
+ output_tags nm.tags
59
+ end
60
+ end
61
+ end
62
+
63
+ desc 'Capture new note.'
64
+ arg_name 'note'
65
+ command :new do |c|
66
+ c.desc 'Insert link.'
67
+ c.flag [:l, :link]
68
+
69
+ c.action do |global_options,options,args|
70
+ nm = Noteman::NoteManager.search
71
+ if args.length > 0
72
+ nm.capture(args.join(' '), options[:link])
73
+ else
74
+ input = nm.fork_editor
75
+ nm.capture input
76
+ end
77
+ end
78
+ end
79
+
80
+ exit run(ARGV)
@@ -0,0 +1,54 @@
1
+ require 'deep_merge'
2
+
3
+ module Noteman
4
+ module Config
5
+
6
+ CONFIG_NAME = ".notemanrc"
7
+
8
+ attr_reader :config
9
+
10
+ def config
11
+ if not defined? @config
12
+ @config = read_from_file
13
+ @config['notes_in'] ||= "~/io"
14
+ @config['view_with'] ||= "Marked 2"
15
+ @config['capture_to'] ||= "capture.md"
16
+ @config['ends_with'] ||= "md"
17
+ @config['fomula'] ||= {}
18
+ @config['fomula']['cheatsheets'] ||= {
19
+ 'tags' => 'cheatsheet'
20
+ }
21
+ @config['fomula']['drafts'] ||= {
22
+ 'tags' => 'draft post',
23
+ 'tags_bool' => 'AND'
24
+ }
25
+
26
+ File.open(home_config, 'w') { |yf| YAML::dump(config, yf) }
27
+ end
28
+ @config
29
+ end
30
+
31
+ def home_config
32
+ if Dir.respond_to?('home')
33
+ File.join(Dir.home, CONFIG_NAME)
34
+ else
35
+ File.join(File.expand_path("~"), CONFIG_NAME)
36
+ end
37
+ end
38
+
39
+ def read_from_file
40
+ c = {}
41
+ dir = Dir.pwd
42
+ while(dir != '/')
43
+ if File.exists? File.join(dir, CONFIG_NAME)
44
+ c = YAML.load_file(File.join(dir, CONFIG_NAME)).deep_merge!(c)
45
+ end
46
+ dir = File.dirname(dir)
47
+ end
48
+ if c.empty? && File.exists?(home_config)
49
+ c = YAML.load_file(home_config)
50
+ end
51
+ c
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,11 @@
1
+ module Noteman
2
+ module Display
3
+ include Config
4
+
5
+ def output_tags(tags)
6
+ tags.keys.each do |tag|
7
+ puts "#{tag} (#{tags[tag]})"
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,109 @@
1
+ require 'curses'
2
+
3
+ module Noteman
4
+ class Finder
5
+ include Curses
6
+
7
+ def initialize
8
+ @opend = false
9
+ end
10
+
11
+ def open
12
+ if @opened
13
+ return self
14
+ end
15
+ init_screen
16
+ cbreak
17
+ noecho
18
+ raw
19
+ @search_box = Window.new(3, cols, 0 ,0)
20
+ @search_box.keypad = true
21
+ draw_search_box
22
+
23
+ @result_box = Window.new(30, cols, 3 ,0)
24
+ draw_result_box
25
+
26
+ @message_box = Window.new(3, cols, 40 ,0)
27
+ draw_message_box
28
+
29
+ @opened = true
30
+ self
31
+ end
32
+
33
+ def close
34
+ @opened = false
35
+ close_screen
36
+ end
37
+
38
+ def find_note
39
+ begin
40
+ open
41
+ text = ''
42
+ selected = 0
43
+ notes = []
44
+ while true
45
+ ch = @search_box.getch
46
+ case ch
47
+ when KEY_RESIZE
48
+ next
49
+ when 10 # enter
50
+ break
51
+ when 127 # backspace
52
+ if text.length > 0
53
+ text = text.slice(0, text.length - 1)
54
+ end
55
+ when KEY_UP #arrow up
56
+ #selected -= 1
57
+ selected == 0 ? selected = notes.length - 1 : selected -= 1
58
+ when KEY_DOWN #arrow down
59
+ selected == notes.length - 1 ? selected = 0 : selected += 1
60
+ else
61
+ if ch.is_a? String
62
+ text += ch
63
+ end
64
+ end
65
+ draw_search_box text
66
+ tags = []
67
+ keywords = []
68
+ text.split.each do |t|
69
+ if t.start_with? '@' and t.length > 1
70
+ tags << t.tr('@', '')
71
+ else
72
+ keywords << t
73
+ end
74
+ end
75
+ notes = NoteManager.search.by_tags(tags).by_keywords(keywords).result
76
+ draw_result_box notes, selected
77
+ end
78
+ notes[selected]
79
+ ensure
80
+ close
81
+ end
82
+ end
83
+
84
+ def draw_search_box(text='')
85
+ @search_box.clear
86
+ @search_box.box('|', '-')
87
+ @search_box.setpos(1, 1)
88
+ @search_box.addstr text
89
+ @search_box.refresh
90
+ end
91
+
92
+ def draw_result_box(results=[], selected_index=0)
93
+ @result_box.clear
94
+ results.each_with_index do |n, i|
95
+ @result_box.setpos(i+1, 1)
96
+ @result_box.attrset(i == selected_index ? A_STANDOUT : A_NORMAL)
97
+ @result_box.addstr "#{n.file}"
98
+ end
99
+ @result_box.refresh
100
+ end
101
+
102
+ def draw_message_box(text='')
103
+ @message_box.clear
104
+ @message_box.setpos(1, 1)
105
+ @message_box.addstr "#{text}"
106
+ @message_box.refresh
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,41 @@
1
+ require 'redcarpet'
2
+ module Noteman
3
+ module MDProcessor
4
+ class StackRenderer < Redcarpet::Render::Base
5
+ attr_reader :items
6
+
7
+ def initialize
8
+ super
9
+ @items = []
10
+ end
11
+
12
+ def header(title, level)
13
+ items << { :text => title, :level => level, :type => :header }
14
+ "#{'#' * level} #{title}\n\n"
15
+ end
16
+
17
+ def paragraph(text)
18
+ items << { :text => text, :type => :paragraph }
19
+ "#{text}\n\n"
20
+ end
21
+
22
+ end
23
+
24
+ def get_metadata(text)
25
+ text =~ /^(---\s*\n.*?\n?)^(---\s*$\n?)/m
26
+ meta = YAML.load($1) if $1
27
+ end
28
+
29
+ def remove_metadata(text)
30
+ text.sub /^(---\s*\n.*?\n?)^(---\s*$\n?)/m, ''
31
+ end
32
+
33
+ def get_md(text)
34
+ sr = StackRenderer.new
35
+ md = Redcarpet::Markdown.new(sr)
36
+
37
+ md.render(remove_metadata text)
38
+ sr.items
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,39 @@
1
+ module Noteman
2
+ class Note
3
+ include MDProcessor, Config
4
+ attr_accessor :content, :metadata, :tags, :body, :file
5
+
6
+ def initialize(file)
7
+ @file = file
8
+ @content = File.read file
9
+ @metadata = get_metadata @content
10
+ @body = remove_metadata @content
11
+ end
12
+
13
+ def tags
14
+ @tags = []
15
+ if metadata and metadata['tags']
16
+ @tags = metadata['tags']
17
+ end
18
+ @tags
19
+ end
20
+
21
+ def with_tags?(tags)
22
+ if metadata and metadata['tags']
23
+ if (tags - metadata['tags']).empty?
24
+ return true
25
+ end
26
+ end
27
+ false
28
+ end
29
+
30
+ def contains?(keywords)
31
+ keywords.all? { |word| body.downcase.include? word.downcase }
32
+ end
33
+
34
+ def view
35
+ system("open -a \"#{config['view_with']}\" #{file}")
36
+ end
37
+
38
+ end
39
+ end
@@ -0,0 +1,133 @@
1
+ module Noteman
2
+ class NoteManager
3
+ include Config
4
+ attr_accessor :notes, :result, :tags
5
+
6
+ def initialize
7
+ @notes = []
8
+ Dir.chdir(File.expand_path(config['notes_in']))
9
+ Dir.glob("*.#{config['ends_with']}").each do |file|
10
+ @notes << Note.new(file)
11
+ end
12
+ end
13
+
14
+ def self.search
15
+ @@manager = NoteManager.new unless defined? @@manager
16
+ @@manager.reset_filter
17
+ end
18
+
19
+ def reset_filter
20
+ @result = []
21
+ @result += @notes
22
+ self
23
+ end
24
+
25
+ def by_tags(tags)
26
+ if tags && tags.length > 0
27
+ @result.delete_if { |note| not note.with_tags? tags }
28
+ end
29
+ self
30
+ end
31
+
32
+ def by_keywords(keywords)
33
+ if keywords && keywords.length > 0
34
+ @result.delete_if { |note| not note.contains? keywords }
35
+ end
36
+ self
37
+ end
38
+
39
+ def search_by_fomular(name)
40
+ fomular = config['fomular'][name]
41
+ if fomular
42
+ search
43
+ tags = fomular['tags'].split(' ')
44
+ keywords = fomular['keywords'].split(' ')
45
+ if tags
46
+ by_tags tags
47
+ end
48
+ if keywords
49
+ by_keywords keywords
50
+ end
51
+ else
52
+ puts "No such fomular defined #{name}."
53
+ end
54
+ self
55
+ end
56
+
57
+ def capture(input, link=nil)
58
+ if link
59
+ content = "[#{input}](#{link})"
60
+ else
61
+ content = input
62
+ end
63
+ open(config['capture_to'], 'a') do |f|
64
+ f << "#{content}\n"
65
+ end
66
+ end
67
+
68
+ def choose(notes)
69
+ if notes.length > 1
70
+ notes.each_with_index do |note, i|
71
+ puts "% 3d: %s" % [i, note.file]
72
+ end
73
+ print "> "
74
+ num = STDIN.gets
75
+ return false if num =~ /^[a-z ]*$/i
76
+ chosen = notes[num.to_i]
77
+ elsif notes.length == 1
78
+ chosen = notes[0]
79
+ else
80
+ chosen = false
81
+ end
82
+ chosen
83
+ end
84
+
85
+ def tags
86
+ if not defined? @tags
87
+ @tags = {}
88
+ notes.each do |note|
89
+ note.tags.each do |tag|
90
+ if not @tags.has_key? tag
91
+ @tags[tag] = 1
92
+ else
93
+ @tags[tag] += 1
94
+ end
95
+ end
96
+ end
97
+ end
98
+ @tags
99
+ end
100
+
101
+ def fork_editor(input="")
102
+ tmpfile = Tempfile.new('note')
103
+
104
+ File.open(tmpfile.path,'w+') do |f|
105
+ f.puts input
106
+ end
107
+
108
+ pid = Process.fork { system("$EDITOR #{tmpfile.path}") }
109
+
110
+ trap("INT") {
111
+ Process.kill(9, pid) rescue Errno::ESRCH
112
+ tmpfile.unlink
113
+ tmpfile.close!
114
+ exit 0
115
+ }
116
+
117
+ Process.wait(pid)
118
+
119
+ begin
120
+ if $?.exitstatus == 0
121
+ input = IO.read(tmpfile.path)
122
+ else
123
+ raise "Cancelled"
124
+ end
125
+ ensure
126
+ tmpfile.close
127
+ tmpfile.unlink
128
+ end
129
+
130
+ input
131
+ end
132
+ end
133
+ end
@@ -1,3 +1,3 @@
1
1
  module Noting
2
- VERSION = '0.0.0'
2
+ VERSION = '0.1.0'
3
3
  end
data/lib/noteman.rb CHANGED
@@ -1,4 +1,7 @@
1
- require 'noteman/version.rb'
2
- require 'noteman/inbox.rb'
3
-
4
- NOTING_CONFIG_NAME = ".notemanrc"
1
+ require 'tempfile'
2
+ require 'noteman/md_processor'
3
+ require 'noteman/config'
4
+ require 'noteman/display'
5
+ require 'noteman/finder'
6
+ require 'noteman/note'
7
+ require 'noteman/note_manager'
metadata CHANGED
@@ -1,15 +1,113 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: noteman
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.0
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Xiaoxing Hu
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-10-31 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2014-11-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: aruba
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: gli
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '='
46
+ - !ruby/object:Gem::Version
47
+ version: 2.12.2
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '='
53
+ - !ruby/object:Gem::Version
54
+ version: 2.12.2
55
+ - !ruby/object:Gem::Dependency
56
+ name: deep_merge
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: redcarpet
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '3.2'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '3.2'
83
+ - !ruby/object:Gem::Dependency
84
+ name: highline
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '1.6'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '1.6'
97
+ - !ruby/object:Gem::Dependency
98
+ name: curses
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '1.0'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '1.0'
13
111
  description: A tool for managing your markdown notes.
14
112
  email: dawnstar.hu@gmail.com
15
113
  executables:
@@ -17,11 +115,17 @@ executables:
17
115
  extensions: []
18
116
  extra_rdoc_files: []
19
117
  files:
118
+ - README.md
20
119
  - bin/note
21
120
  - lib/noteman.rb
22
- - lib/noteman/inbox.rb
121
+ - lib/noteman/config.rb
122
+ - lib/noteman/display.rb
123
+ - lib/noteman/finder.rb
124
+ - lib/noteman/md_processor.rb
125
+ - lib/noteman/note.rb
126
+ - lib/noteman/note_manager.rb
23
127
  - lib/noteman/version.rb
24
- homepage:
128
+ homepage: https://github.com/xiaoxinghu/noteman
25
129
  licenses:
26
130
  - MIT
27
131
  metadata: {}
@@ -41,7 +145,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
41
145
  version: '0'
42
146
  requirements: []
43
147
  rubyforge_project:
44
- rubygems_version: 2.4.1
148
+ rubygems_version: 2.4.2
45
149
  signing_key:
46
150
  specification_version: 4
47
151
  summary: You advanced note manager.
data/lib/noteman/inbox.rb DELETED
@@ -1,5 +0,0 @@
1
- class Inbox
2
- def hi
3
- puts "Hi, this is your inbox."
4
- end
5
- end