soywiki 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +9 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +25 -0
- data/README.md +3 -0
- data/Rakefile +25 -0
- data/bin/soywiki +9 -0
- data/bin/soywiki-pages-linking-in +29 -0
- data/bin/soywiki-rename +53 -0
- data/bin/soywiki-unfurl +36 -0
- data/lib/soywiki.rb +8 -0
- data/lib/soywiki.vim +455 -0
- data/soywiki.gemspec +22 -0
- metadata +91 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
couchrest (1.0.1)
|
5
|
+
json (>= 1.4.6)
|
6
|
+
mime-types (>= 1.15)
|
7
|
+
rest-client (>= 1.5.1)
|
8
|
+
haml (3.0.25)
|
9
|
+
json (1.5.1)
|
10
|
+
mime-types (1.16)
|
11
|
+
rack (1.2.1)
|
12
|
+
rest-client (1.6.1)
|
13
|
+
mime-types (>= 1.16)
|
14
|
+
sinatra (1.1.2)
|
15
|
+
rack (~> 1.1)
|
16
|
+
tilt (~> 1.2)
|
17
|
+
tilt (1.2.2)
|
18
|
+
|
19
|
+
PLATFORMS
|
20
|
+
ruby
|
21
|
+
|
22
|
+
DEPENDENCIES
|
23
|
+
couchrest
|
24
|
+
haml
|
25
|
+
sinatra
|
data/README.md
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
$LOAD_PATH.unshift File.join(File.dirname(__FILE__), 'lib')
|
2
|
+
require 'couchrest'
|
3
|
+
require 'yaml'
|
4
|
+
require 'json'
|
5
|
+
require 'rake'
|
6
|
+
require 'rake/testtask'
|
7
|
+
require 'bundler'
|
8
|
+
# require 'soywiki'
|
9
|
+
|
10
|
+
Bundler::GemHelper.install_tasks
|
11
|
+
|
12
|
+
desc "Start Sinatra webapp"
|
13
|
+
task :sinatra do
|
14
|
+
# TODO
|
15
|
+
end
|
16
|
+
|
17
|
+
desc "Run tests"
|
18
|
+
task :test do
|
19
|
+
$:.unshift File.expand_path("test")
|
20
|
+
MiniTest::Unit.autorun
|
21
|
+
end
|
22
|
+
|
23
|
+
task :default => :test
|
24
|
+
|
25
|
+
|
data/bin/soywiki
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: utf-8
|
3
|
+
|
4
|
+
class String
|
5
|
+
def is_namespaced?
|
6
|
+
self.split(".").size == 2
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def inbound_links_to?(file, page_title)
|
11
|
+
return false unless File.file?(file)
|
12
|
+
return false if (file =~ /(\.swo|\.swp)$/ || file =~ /^\./)
|
13
|
+
body = File.read(file)
|
14
|
+
body =~ /[\A\s\n\b]#{page_title}\b/
|
15
|
+
end
|
16
|
+
|
17
|
+
target_page = ARGV.first
|
18
|
+
|
19
|
+
if target_page.is_namespaced?
|
20
|
+
namespace, page = *target_page.split(".")
|
21
|
+
# find all files in this name space
|
22
|
+
Dir.glob("#{namespace}.*").select do |file|
|
23
|
+
inbound_links_to?(file, target_page) || inbound_links_to?(file, ".#{page}")
|
24
|
+
end.each {|file| puts file}
|
25
|
+
else
|
26
|
+
Dir.glob("*").select do |file|
|
27
|
+
inbound_links_to?(file, target_page)
|
28
|
+
end.each {|file| puts file}
|
29
|
+
end
|
data/bin/soywiki-rename
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
oldname, newname = *ARGV
|
3
|
+
|
4
|
+
class String
|
5
|
+
def is_namespaced?
|
6
|
+
self.split(".").size == 2
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
target_files = `grep -lF '#{oldname}' *`.strip.split(/\n/)
|
11
|
+
target_files.each do |file|
|
12
|
+
text = File.read(file)
|
13
|
+
text.gsub!(/\b#{oldname}\b/, newname)
|
14
|
+
File.open(file, 'w') {|f| f.puts text}
|
15
|
+
end
|
16
|
+
|
17
|
+
# deal with links without namespace
|
18
|
+
|
19
|
+
old_short = oldname.split(".")[1]
|
20
|
+
new_short = newname.split(".")[1]
|
21
|
+
|
22
|
+
if old_short && !new_short
|
23
|
+
# where going from a namespaced name to a top-level name
|
24
|
+
old_namespace = oldname.split(".")[0]
|
25
|
+
target_files = `grep -lF '\<#{old_short}\>' *`.strip.split(/\n/)
|
26
|
+
target_files.each do |file|
|
27
|
+
text = File.read(file)
|
28
|
+
text.gsub!(/\b#{old_short}\b/, newname)
|
29
|
+
File.open(file, 'w') {|f| f.puts text}
|
30
|
+
end
|
31
|
+
# change all the .Wikiwords in the newname file to fully namespaced
|
32
|
+
# links with namespace of newname.downcase
|
33
|
+
if File.exist?(newname)
|
34
|
+
text = File.read(newname)
|
35
|
+
#text.gsub!(relative_wiki_word, "#{newname.downcase}.#{$1}")
|
36
|
+
# ".Pear".gsub!(/\A\.([A-Z][a-z]+[A-Z]\w*)/, "TEST.#{$1}")
|
37
|
+
text.gsub!(/([\A\s\n\b])\.([A-Z][a-z]+[A-Z]\w*)/, '\1' + newname.downcase + '.\2')
|
38
|
+
File.open(newname, 'w') {|f| f.puts text}
|
39
|
+
end
|
40
|
+
elsif !old_short && new_short
|
41
|
+
# where going from a top-level name to a namespaced one
|
42
|
+
# no action needed
|
43
|
+
elsif !old_short && !new_short
|
44
|
+
# no action needed
|
45
|
+
elsif old_short && new_short
|
46
|
+
target_files = `grep -lF '#{old_short}' *`.strip.split(/\n/)
|
47
|
+
puts target_files.inspect
|
48
|
+
target_files.each do |file|
|
49
|
+
text = File.read(file)
|
50
|
+
text.gsub!(/\b#{old_short}\b/, new_short)
|
51
|
+
File.open(file, 'w') {|f| f.puts text}
|
52
|
+
end
|
53
|
+
end
|
data/bin/soywiki-unfurl
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# takes any wiki link that stands alone on a line and expands it
|
4
|
+
#
|
5
|
+
WIKI_LINK_PATTERN = /^\s*(([a-z]+\.)?[A-Z][a-z]+[A-Z]\w*|\.[A-Z][a-z]+[A-Z]\w*)\s*$/
|
6
|
+
|
7
|
+
PROCESSED_FILES = []
|
8
|
+
def unfurl(file)
|
9
|
+
PROCESSED_FILES << file
|
10
|
+
lines = File.readlines(file)
|
11
|
+
lines.shift 2
|
12
|
+
lines = lines.join.strip.split("\n")
|
13
|
+
lines.each do |line|
|
14
|
+
if line =~ WIKI_LINK_PATTERN
|
15
|
+
link = line.strip
|
16
|
+
if link =~ /^\./ # short link in namespace (relative link)
|
17
|
+
namespace = file.split(".")[0]
|
18
|
+
link = [namespace, link].join
|
19
|
+
end
|
20
|
+
if File.file?(link) && !PROCESSED_FILES.include?(link)
|
21
|
+
unfurl link # recursive
|
22
|
+
elsif PROCESSED_FILES.include?(link)
|
23
|
+
puts "#{link} [already expanded]"
|
24
|
+
else
|
25
|
+
puts "#{link} [no file found]"
|
26
|
+
end
|
27
|
+
else
|
28
|
+
puts line
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
ARGV.each do |file|
|
34
|
+
unfurl(file)
|
35
|
+
end
|
36
|
+
|
data/lib/soywiki.rb
ADDED
data/lib/soywiki.vim
ADDED
@@ -0,0 +1,455 @@
|
|
1
|
+
" Vim script that turns Vim into a personal wiki
|
2
|
+
" Maintainer: Daniel Choi <dhchoi@gmail.com>
|
3
|
+
" License: MIT License (c) 2011 Daniel Choi
|
4
|
+
|
5
|
+
" this matched namedspaced WikiWords, top-level WikiWords, and relative .WikiWords in a
|
6
|
+
" namespace
|
7
|
+
let s:wiki_link_pattern = '\C\<\([a-z]\+\.\)\?[A-Z][a-z]\+[A-Z]\w*\>\|\.[A-Z][a-z]\+[A-Z]\w*\>'
|
8
|
+
|
9
|
+
let s:rename_links_command = 'soywiki-rename '
|
10
|
+
let s:find_pages_linking_in_command = 'soywiki-pages-linking-in '
|
11
|
+
let s:search_for_link = ""
|
12
|
+
|
13
|
+
|
14
|
+
func! s:trimString(string)
|
15
|
+
let string = substitute(a:string, '\s\+$', '', '')
|
16
|
+
return substitute(string, '^\s\+', '', '')
|
17
|
+
endfunc
|
18
|
+
|
19
|
+
func! s:page_title()
|
20
|
+
let title_line = getline(1)
|
21
|
+
return s:trimString(title_line)
|
22
|
+
endfunc
|
23
|
+
|
24
|
+
func! s:page_namespace()
|
25
|
+
let segments = split(s:page_title(), '\.')
|
26
|
+
return get(segments, 0)
|
27
|
+
endfunc
|
28
|
+
|
29
|
+
func! s:title_without_namespace(page_title)
|
30
|
+
if len(split(a:page_title, '\.')) == 2
|
31
|
+
return "." . get(split(a:page_title, '\.'), 1)
|
32
|
+
else
|
33
|
+
return a:page_title
|
34
|
+
endif
|
35
|
+
endfunc
|
36
|
+
|
37
|
+
func! s:is_wiki_page()
|
38
|
+
let title_line = getline(1)
|
39
|
+
return (match(title_line, s:wiki_link_pattern) == 0)
|
40
|
+
endfunc
|
41
|
+
func! s:save_page()
|
42
|
+
" write
|
43
|
+
endfunc
|
44
|
+
|
45
|
+
func! s:list_pages()
|
46
|
+
let s:search_for_link = ""
|
47
|
+
call s:get_page_list()
|
48
|
+
call s:page_list_window("CompletePageInSelectionWindow", "Select page: ")
|
49
|
+
endfunc
|
50
|
+
|
51
|
+
func! s:link_under_cursor()
|
52
|
+
let link = expand("<cWORD>")
|
53
|
+
let link = substitute(link, '[^[:alnum:]]*$', '', '')
|
54
|
+
" see if he have a namespaced link
|
55
|
+
if (match(link, '^\.')) == 0
|
56
|
+
" find the namespace from the page title
|
57
|
+
let link = s:page_namespace() . link
|
58
|
+
endif
|
59
|
+
|
60
|
+
let link = substitute(link, '^[^\.[:alnum:]]', '', '') " link may begin with period
|
61
|
+
return link
|
62
|
+
endfunc
|
63
|
+
|
64
|
+
" follows a camel case link to a new page
|
65
|
+
func! s:follow_link(split)
|
66
|
+
let link = s:link_under_cursor()
|
67
|
+
if match(link, s:wiki_link_pattern) == -1
|
68
|
+
let link = s:find_next_wiki_link(0)
|
69
|
+
endif
|
70
|
+
call s:load_page(link, a:split)
|
71
|
+
endfunc
|
72
|
+
|
73
|
+
func! s:follow_link_under_cursor(split)
|
74
|
+
let link = s:link_under_cursor()
|
75
|
+
if match(link, s:wiki_link_pattern) == -1
|
76
|
+
echom "Not a wiki link"
|
77
|
+
return
|
78
|
+
endif
|
79
|
+
call s:load_page(link, a:split)
|
80
|
+
endfunc
|
81
|
+
|
82
|
+
func! s:find_next_wiki_link(backward)
|
83
|
+
let n = 0
|
84
|
+
let result = search(s:wiki_link_pattern, 'w' . (a:backward == 1 ? 'b' : ''))
|
85
|
+
if (result == 0)
|
86
|
+
return
|
87
|
+
end
|
88
|
+
return s:link_under_cursor()
|
89
|
+
endfunc
|
90
|
+
|
91
|
+
func! s:load_page(page, split)
|
92
|
+
let page = a:page
|
93
|
+
if (s:is_wiki_page())
|
94
|
+
write
|
95
|
+
endif
|
96
|
+
if (!filereadable(page))
|
97
|
+
" create the file
|
98
|
+
call writefile([a:page, '', ''], page)
|
99
|
+
endif
|
100
|
+
if (a:split == 2)
|
101
|
+
exec "vsplit ". page
|
102
|
+
else
|
103
|
+
exec "split ". page
|
104
|
+
endif
|
105
|
+
if (a:split == 0)
|
106
|
+
wincmd p
|
107
|
+
close
|
108
|
+
endif
|
109
|
+
endfunc
|
110
|
+
|
111
|
+
func! s:delete_page()
|
112
|
+
let file = bufname('%')
|
113
|
+
let bufnr = bufnr('%')
|
114
|
+
call delete(file)
|
115
|
+
call system("git commit " . bufname('%') . " -m 'deletion'")
|
116
|
+
" go to most recently saved
|
117
|
+
" call feedkeys("\<C-o>")
|
118
|
+
let target = s:trimString(system("ls -t | head -1"))
|
119
|
+
exec "e " . target
|
120
|
+
exec "bdelete " . bufnr
|
121
|
+
redraw
|
122
|
+
echom "Deleted " . file
|
123
|
+
endfunc
|
124
|
+
|
125
|
+
func! s:prompt_for_wiki_word(prompt, default)
|
126
|
+
let input = s:trimString(input(a:prompt, a:default))
|
127
|
+
while match(input, s:wiki_link_pattern) == -1
|
128
|
+
let input = s:trimString(input("Must be a WikiWord! Press CTRL-c to cancel. " . a:prompt , a:default))
|
129
|
+
endwhile
|
130
|
+
return input
|
131
|
+
endfunc
|
132
|
+
|
133
|
+
func! s:rename_page()
|
134
|
+
let file = bufname('%')
|
135
|
+
let newname = s:prompt_for_wiki_word("Rename file: ", l:file)
|
136
|
+
if (filereadable(newname))
|
137
|
+
exe "echom '" . newname . " already exists!'"
|
138
|
+
return
|
139
|
+
endif
|
140
|
+
call system("git mv " . l:file . " " . newname)
|
141
|
+
exec "e ". newname
|
142
|
+
" replace all existing inbound links
|
143
|
+
" TODO replace this with a ruby script
|
144
|
+
call system(s:rename_links_command . file . " " . newname)
|
145
|
+
call system("git commit -am 'rename wiki page'")
|
146
|
+
e!
|
147
|
+
endfunc
|
148
|
+
|
149
|
+
func! s:create_page()
|
150
|
+
let newname = s:prompt_for_wiki_word("New page title: ", "")
|
151
|
+
if (filereadable(newname))
|
152
|
+
exe "echom '" . newname . " already exists!'"
|
153
|
+
return
|
154
|
+
endif
|
155
|
+
call writefile([newname, '', ''], newname)
|
156
|
+
exec "e ". newname
|
157
|
+
endfunc
|
158
|
+
|
159
|
+
func! s:save_revision()
|
160
|
+
call system("git add " . bufname('%'))
|
161
|
+
call system("git commit " . bufname('%') . " -m 'edit'")
|
162
|
+
endfunc
|
163
|
+
|
164
|
+
func! s:show_revision_history(stat)
|
165
|
+
" maybe later allow --stat
|
166
|
+
if (a:stat)
|
167
|
+
exec ":!git log --stat " . bufname('%')
|
168
|
+
else
|
169
|
+
exec ":!git log --color-words -p " . bufname('%')
|
170
|
+
end
|
171
|
+
endfunc
|
172
|
+
|
173
|
+
func! s:show_blame()
|
174
|
+
exec ":!git blame " . bufname('%')
|
175
|
+
endfunc
|
176
|
+
|
177
|
+
|
178
|
+
" -------------------------------------------------------------------------------
|
179
|
+
" select Page
|
180
|
+
|
181
|
+
func! s:get_page_list()
|
182
|
+
if len(bufname('%')) == 0
|
183
|
+
let s:page_list = split(system("ls -t"), "\n")
|
184
|
+
else
|
185
|
+
let s:page_list = split(system("ls -t | grep -vF '" . bufname('%') . "'" ), "\n")
|
186
|
+
endif
|
187
|
+
endfunction
|
188
|
+
|
189
|
+
func! s:pages_in_this_namespace(pages)
|
190
|
+
let namespace = s:page_namespace()
|
191
|
+
let pages = filter( a:pages, 'v:val =~ "^' . namespace . '"')
|
192
|
+
" strip leading namespace
|
193
|
+
let pages = map( pages, "substitute(v:val, '^" . namespace . "\.', '', '') " )
|
194
|
+
return pages
|
195
|
+
endfunc
|
196
|
+
|
197
|
+
func! s:reduce_matches()
|
198
|
+
if (!exists("s:matching_pages"))
|
199
|
+
return
|
200
|
+
endif
|
201
|
+
let fragment = expand("<cWORD>")
|
202
|
+
let reduced_pages = filter( s:matching_pages, 'v:val =~ "^' . fragment . '"')
|
203
|
+
" find the first namespace in the list
|
204
|
+
let namespaced_matches = filter( s:matching_pages, 'v:val =~ "^' . fragment . '\."')
|
205
|
+
if (len(namespaced_matches) == 0)
|
206
|
+
return
|
207
|
+
elseif match(fragment, '^[A-Z]') == -1 && match(fragment, '\.' == -1)
|
208
|
+
" we're beginning to type a namespace
|
209
|
+
let namespace = get(split(get(namespaced_matches, 0), '\.'), 0)
|
210
|
+
let namespace .= "."
|
211
|
+
call feedkeys( "BcW". namespace. "\<C-x>\<C-u>\<C-p>" , "t")
|
212
|
+
else
|
213
|
+
" we're tabbing to auto complete the term, not find a namespace
|
214
|
+
return
|
215
|
+
endif
|
216
|
+
endfunc
|
217
|
+
|
218
|
+
function! s:page_list_window(complete_function, prompt)
|
219
|
+
topleft split page-list-buffer
|
220
|
+
setlocal buftype=nofile
|
221
|
+
setlocal noswapfile
|
222
|
+
setlocal modifiable
|
223
|
+
resize 1
|
224
|
+
inoremap <silent> <buffer> <cr> <Esc>:call <SID>select_page()<CR>
|
225
|
+
inoremap <buffer> <Tab> <Esc>:call <SID>reduce_matches()<cr>
|
226
|
+
noremap <buffer> q <Esc>:close<cr>
|
227
|
+
exec "setlocal completefunc=" . a:complete_function
|
228
|
+
" c-p clears the line
|
229
|
+
call setline(1, a:prompt)
|
230
|
+
normal $
|
231
|
+
call feedkeys("a\<c-x>\<c-u>\<c-p>", 't')
|
232
|
+
" call feedkeys("a", 't')
|
233
|
+
endfunction
|
234
|
+
|
235
|
+
function! CompletePage(findstart, base)
|
236
|
+
let s:matching_pages = s:page_list[:]
|
237
|
+
let possible_period = getline('.')[col('.') - 2]
|
238
|
+
if (possible_period == '.')
|
239
|
+
" filter to pages in this namespace
|
240
|
+
let s:matching_pages = s:pages_in_this_namespace(s:matching_pages)
|
241
|
+
endif
|
242
|
+
if a:findstart
|
243
|
+
" locate the start of the word
|
244
|
+
let line = getline('.')
|
245
|
+
let start = col('.') - 1
|
246
|
+
while start > 0 && line[start - 1] =~ '[[:alnum:]]'
|
247
|
+
let start -= 1
|
248
|
+
endwhile
|
249
|
+
return start
|
250
|
+
else
|
251
|
+
let base = s:trimString(a:base)
|
252
|
+
if (base == '')
|
253
|
+
return s:matching_pages
|
254
|
+
else
|
255
|
+
let res = []
|
256
|
+
for m in s:matching_pages
|
257
|
+
if m =~ '\c' . base
|
258
|
+
call add(res, m)
|
259
|
+
endif
|
260
|
+
endfor
|
261
|
+
return res
|
262
|
+
endif
|
263
|
+
endif
|
264
|
+
endfun
|
265
|
+
|
266
|
+
function! CompletePageInSelectionWindow(findstart, base)
|
267
|
+
let s:matching_pages = s:page_list[:]
|
268
|
+
if a:findstart
|
269
|
+
" locate the start of the word
|
270
|
+
let line = getline('.')
|
271
|
+
let start = col('.') - 1
|
272
|
+
while start > 0 && line[start - 1] =~ '[[:alnum:]\.]'
|
273
|
+
let start -= 1
|
274
|
+
endwhile
|
275
|
+
return start
|
276
|
+
else
|
277
|
+
let base = s:trimString(a:base)
|
278
|
+
if (base == '')
|
279
|
+
return s:matching_pages
|
280
|
+
else
|
281
|
+
let res = []
|
282
|
+
for m in s:matching_pages
|
283
|
+
if m =~ '\c' . base
|
284
|
+
call add(res, m)
|
285
|
+
endif
|
286
|
+
endfor
|
287
|
+
return res
|
288
|
+
endif
|
289
|
+
endif
|
290
|
+
endfun
|
291
|
+
|
292
|
+
function! s:select_page()
|
293
|
+
let page = s:trimString( get(split(getline(line('.')), ": "), 1) )
|
294
|
+
close
|
295
|
+
if (page == '0' || page == '') " no selection
|
296
|
+
return
|
297
|
+
end
|
298
|
+
let match = ""
|
299
|
+
for item in s:matching_pages
|
300
|
+
if (item == page)
|
301
|
+
call s:load_page(page, 0)
|
302
|
+
|
303
|
+
break
|
304
|
+
end
|
305
|
+
endfor
|
306
|
+
echo s:search_for_link
|
307
|
+
if len(s:search_for_link) > 0
|
308
|
+
call search('\<' . s:search_for_link . '\>')
|
309
|
+
endif
|
310
|
+
endfunction
|
311
|
+
|
312
|
+
"------------------------------------------------------------------------
|
313
|
+
" PAGES LINKING IN
|
314
|
+
"
|
315
|
+
" this logic could be more precise, in cases where pages have same name
|
316
|
+
" in different namespaces
|
317
|
+
|
318
|
+
func! s:list_pages_linking_in()
|
319
|
+
let s:pages_linking_in = split(system(s:find_pages_linking_in_command . s:page_title()), "\n")
|
320
|
+
let s:search_for_link = s:title_without_namespace( s:page_title())
|
321
|
+
if len(s:pages_linking_in) == 1
|
322
|
+
let file = get(s:pages_linking_in, 0)
|
323
|
+
write
|
324
|
+
exec "e " . file
|
325
|
+
" not perfectly targeted but OK for now
|
326
|
+
call search(s:search_for_link)
|
327
|
+
elseif len(s:pages_linking_in) == 0
|
328
|
+
echom "No pages link to " . s:page_title() . "!"
|
329
|
+
else
|
330
|
+
call s:page_list_window("CompletePagesLinkingIn_InSelectionWindow", "Pages that link to " . s:page_title() . ": ")
|
331
|
+
endif
|
332
|
+
endfunc
|
333
|
+
|
334
|
+
function! CompletePagesLinkingIn_InSelectionWindow(findstart, base)
|
335
|
+
" todo, this must be smarter, deal with different namespaces
|
336
|
+
let s:matching_pages = s:pages_linking_in[:]
|
337
|
+
if a:findstart
|
338
|
+
" locate the start of the word
|
339
|
+
let line = getline('.')
|
340
|
+
let start = col('.') - 1
|
341
|
+
while start > 0 && line[start - 1] =~ '[[:alnum:]\.]'
|
342
|
+
let start -= 1
|
343
|
+
endwhile
|
344
|
+
return start
|
345
|
+
else
|
346
|
+
let base = s:trimString(a:base)
|
347
|
+
if (base == '')
|
348
|
+
return s:matching_pages
|
349
|
+
else
|
350
|
+
let res = []
|
351
|
+
for m in s:matching_pages
|
352
|
+
if m =~ '\c' . base
|
353
|
+
call add(res, m)
|
354
|
+
endif
|
355
|
+
endfor
|
356
|
+
return res
|
357
|
+
endif
|
358
|
+
endif
|
359
|
+
endfun
|
360
|
+
|
361
|
+
"------------------------------------------------------------------------
|
362
|
+
" This opens a new buffer with all the lines with just WikiLinks on them
|
363
|
+
" expanded (recursively). This is not a wiki buffer but a text buffer
|
364
|
+
|
365
|
+
func! s:unfurl()
|
366
|
+
let res = system("soywiki-unfurl " . bufname('%'))
|
367
|
+
vertical botright new
|
368
|
+
setlocal buftype=nofile "scratch buffer for viewing; user can write
|
369
|
+
put =res
|
370
|
+
1delete
|
371
|
+
normal 1G
|
372
|
+
endfunc
|
373
|
+
|
374
|
+
"------------------------------------------------------------------------
|
375
|
+
|
376
|
+
func! s:open_href()
|
377
|
+
let pattern = 'https\?:[^ >)\]]\+'
|
378
|
+
let line = search(pattern, 'cw')
|
379
|
+
let href = matchstr(getline(line('.')), pattern)
|
380
|
+
let command = g:SoyWiki#browser_command . " '" . href . "' "
|
381
|
+
call system(command)
|
382
|
+
echom command
|
383
|
+
endfunc
|
384
|
+
|
385
|
+
"------------------------------------------------------------------------
|
386
|
+
|
387
|
+
func! s:global_mappings()
|
388
|
+
noremap <leader>m :call <SID>list_pages()<CR>
|
389
|
+
noremap <leader>M :call <SID>list_pages_linking_in()<CR>
|
390
|
+
noremap <silent> <leader>o :call <SID>open_href()<cr>
|
391
|
+
endfunc
|
392
|
+
|
393
|
+
" this checks if the buffer is a SoyWiki file (from firstline)
|
394
|
+
" and then turns on syntax coloring and mappings as necessary
|
395
|
+
func! s:prep_buffer()
|
396
|
+
if (s:is_wiki_page())
|
397
|
+
set textwidth=72
|
398
|
+
nnoremap <buffer> <cr> :call <SID>follow_link_under_cursor(0)<cr>
|
399
|
+
nnoremap <buffer> - :call <SID>follow_link_under_cursor(1)<cr>
|
400
|
+
nnoremap <buffer> \| :call <SID>follow_link_under_cursor(2)<cr>
|
401
|
+
noremap <buffer> <leader>f :call <SID>follow_link(0)<CR>
|
402
|
+
noremap <buffer> <leader>n :call <SID>find_next_wiki_link(0)<CR>
|
403
|
+
noremap <buffer> <leader>p :call <SID>find_next_wiki_link(1)<CR>
|
404
|
+
noremap <leader>c :call <SID>create_page()<CR>
|
405
|
+
command! -buffer SWDelete :call s:delete_page()
|
406
|
+
command! -buffer SWRename :call s:rename_page()
|
407
|
+
command! -buffer SWLog :call s:show_revision_history(0)
|
408
|
+
noremap <buffer> <leader>l :call <SID>show_revision_history(0)<CR>
|
409
|
+
command! -buffer SWLogStat :call s:show_revision_history(1)
|
410
|
+
command! -buffer SWBlame :call s:show_blame()
|
411
|
+
noremap <buffer> <leader>x :call <SID>unfurl()<CR>
|
412
|
+
set nu
|
413
|
+
setlocal completefunc=CompletePage
|
414
|
+
augroup <buffer>
|
415
|
+
au!
|
416
|
+
autocmd BufWritePost <buffer> call s:save_revision()
|
417
|
+
augroup END
|
418
|
+
endif
|
419
|
+
endfunc
|
420
|
+
|
421
|
+
func! s:highlight_wikiwords()
|
422
|
+
if (s:is_wiki_page())
|
423
|
+
exe "match Comment /". s:wiki_link_pattern. "/"
|
424
|
+
else
|
425
|
+
match none " not sure if this works
|
426
|
+
endif
|
427
|
+
endfunc
|
428
|
+
|
429
|
+
call s:global_mappings()
|
430
|
+
|
431
|
+
autocmd WinEnter * call s:highlight_wikiwords()
|
432
|
+
autocmd BufEnter * call s:prep_buffer()
|
433
|
+
|
434
|
+
" load most recent page
|
435
|
+
let pages = split(system("ls -t" ), "\n")
|
436
|
+
let start_page = len(pages) > 0 ? get(pages, 0) : "HomePage"
|
437
|
+
call s:load_page(start_page, 0)
|
438
|
+
|
439
|
+
if (!isdirectory(".git"))
|
440
|
+
call system("git init")
|
441
|
+
echom "Created .git repository to store revisions"
|
442
|
+
endif
|
443
|
+
|
444
|
+
if !exists("g:SoyWiki#browser_command")
|
445
|
+
for cmd in ["gnome-open", "open"]
|
446
|
+
if executable(cmd)
|
447
|
+
let g:SoyWiki#browser_command = cmd
|
448
|
+
break
|
449
|
+
endif
|
450
|
+
endfor
|
451
|
+
if !exists("g:SoyWiki#browser_command")
|
452
|
+
echom "Can't find the to open your web browser."
|
453
|
+
endif
|
454
|
+
endif
|
455
|
+
|
data/soywiki.gemspec
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = "soywiki"
|
6
|
+
s.version = "0.0.1"
|
7
|
+
s.platform = Gem::Platform::RUBY
|
8
|
+
s.authors = ["Daniel Choi"]
|
9
|
+
s.email = ["dhchoi@gmail.com"]
|
10
|
+
s.homepage = "http://danielchoi.com/software/soywiki.html"
|
11
|
+
s.summary = %q{Wiki with Vim interface and Git repo}
|
12
|
+
s.description = %q{A personal and collaborative wiki for Vim users}
|
13
|
+
|
14
|
+
s.rubyforge_project = "soywiki"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
s.add_dependency 'couchrest'
|
22
|
+
end
|
metadata
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: soywiki
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
version: 0.0.1
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Daniel Choi
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2011-02-07 00:00:00 -05:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: couchrest
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
segments:
|
29
|
+
- 0
|
30
|
+
version: "0"
|
31
|
+
type: :runtime
|
32
|
+
version_requirements: *id001
|
33
|
+
description: A personal and collaborative wiki for Vim users
|
34
|
+
email:
|
35
|
+
- dhchoi@gmail.com
|
36
|
+
executables:
|
37
|
+
- soywiki
|
38
|
+
- soywiki-pages-linking-in
|
39
|
+
- soywiki-rename
|
40
|
+
- soywiki-unfurl
|
41
|
+
extensions: []
|
42
|
+
|
43
|
+
extra_rdoc_files: []
|
44
|
+
|
45
|
+
files:
|
46
|
+
- .gitignore
|
47
|
+
- Gemfile
|
48
|
+
- Gemfile.lock
|
49
|
+
- README.md
|
50
|
+
- Rakefile
|
51
|
+
- bin/soywiki
|
52
|
+
- bin/soywiki-pages-linking-in
|
53
|
+
- bin/soywiki-rename
|
54
|
+
- bin/soywiki-unfurl
|
55
|
+
- lib/soywiki.rb
|
56
|
+
- lib/soywiki.vim
|
57
|
+
- soywiki.gemspec
|
58
|
+
has_rdoc: true
|
59
|
+
homepage: http://danielchoi.com/software/soywiki.html
|
60
|
+
licenses: []
|
61
|
+
|
62
|
+
post_install_message:
|
63
|
+
rdoc_options: []
|
64
|
+
|
65
|
+
require_paths:
|
66
|
+
- lib
|
67
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
68
|
+
none: false
|
69
|
+
requirements:
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
segments:
|
73
|
+
- 0
|
74
|
+
version: "0"
|
75
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
76
|
+
none: false
|
77
|
+
requirements:
|
78
|
+
- - ">="
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
segments:
|
81
|
+
- 0
|
82
|
+
version: "0"
|
83
|
+
requirements: []
|
84
|
+
|
85
|
+
rubyforge_project: soywiki
|
86
|
+
rubygems_version: 1.3.7
|
87
|
+
signing_key:
|
88
|
+
specification_version: 3
|
89
|
+
summary: Wiki with Vim interface and Git repo
|
90
|
+
test_files: []
|
91
|
+
|