soywiki 0.0.9 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/README.markdown +77 -24
- data/bin/soywiki-expand +5 -2
- data/bin/soywiki-ls-t +8 -6
- data/bin/soywiki-pages-linking-in +14 -18
- data/bin/soywiki-rename +40 -50
- data/lib/soywiki.rb +2 -9
- data/lib/soywiki.vim +171 -178
- metadata +4 -5
- data/website/soywiki.html +0 -446
data/.gitignore
CHANGED
data/README.markdown
CHANGED
@@ -44,12 +44,17 @@ SoyWiki is free and open source.
|
|
44
44
|
* a recent version of Vim (SoyWiki is developed against Vim 7.2 and 7.3)
|
45
45
|
* a recent version of Ruby (SoyWiki is developed using Ruby 1.9.2)
|
46
46
|
* RubyGems (if Ruby version is older than 1.9)
|
47
|
-
* a recent version of Git (1.7.0.4 or above to be safe)
|
47
|
+
* a recent version of [Git][git] (1.7.0.4 or above to be safe)
|
48
|
+
|
49
|
+
[git]:http://git-scm.com/
|
48
50
|
|
49
51
|
The current version of SoyWiki assumes a Unix environment.
|
50
52
|
|
51
53
|
To use SoyWiki you should be fairly good at using Vim.
|
52
54
|
|
55
|
+
Most of SoyWiki's commands should work even if you don't have Git
|
56
|
+
installed. But the revision history commands will not.
|
57
|
+
|
53
58
|
## Installation
|
54
59
|
|
55
60
|
gem install soywiki
|
@@ -96,28 +101,37 @@ just run `soywiki`.
|
|
96
101
|
For basic use, SoyWiki works exactly like a typical wiki.
|
97
102
|
|
98
103
|
You write text, and when you want to create a new wiki page, you come up
|
99
|
-
with a WikiWord for it and format it in CamelCase. The WikiLink you
|
100
|
-
|
101
|
-
|
102
|
-
|
104
|
+
with a WikiWord for it and format it in CamelCase. The WikiLink you just
|
105
|
+
typed will automatically be syntax-highlighted, and pressing ENTER on it
|
106
|
+
will take you to the new page. Creating WikiWords and pressing ENTER on
|
107
|
+
them is how you create wiki pages and link them together. You'll be
|
103
108
|
surprised at how powerful this simple mechanism is for organizing your
|
104
109
|
notes.
|
105
110
|
|
111
|
+
In SoyWiki, a wiki page is a simple text file that has a WikiWord title
|
112
|
+
on the first line (don't alter this line) and any text your want to
|
113
|
+
insert below that. SoyWiki will create stub WikiPages for you
|
114
|
+
automatically as you traverse WikiLinks that don't yet reference any
|
115
|
+
content.
|
116
|
+
|
106
117
|
That's all you need to know to get started.
|
107
118
|
|
108
119
|
## Wiki navigation
|
109
120
|
|
110
|
-
Because SoyWiki is not just wiki but also a Vim program, it lets you
|
111
|
-
work a lot faster and with more economy than browser-based wikis.
|
112
|
-
|
113
121
|
You can navigate a SoyWiki wiki very quickly with the following
|
114
|
-
commands
|
122
|
+
commands:
|
115
123
|
|
116
|
-
* `CTRL-
|
124
|
+
* `CTRL-k` and `CTRL-j` move the cursor directly to the next or previous WikiLink on the page
|
117
125
|
* `ENTER` follows the WikiLink under the cursor
|
118
126
|
* `,f` follows the first WikiLink after the cursor
|
119
|
-
*
|
120
|
-
*
|
127
|
+
* `CTRL-l` opens a WikiLink in a split window
|
128
|
+
* `CTRL-n` does the same, but in a vertical split window
|
129
|
+
* Both `q` and `CTRL-h` close a split window
|
130
|
+
|
131
|
+
These key mappings may not be very mnemonic, but they are easy to
|
132
|
+
memorize through muscle memory and were chosen to keep the hands
|
133
|
+
stationary and the fingers near home position on a QWERTY keyboard while
|
134
|
+
navigating the wiki.
|
121
135
|
|
122
136
|
You can also use Vim's jump motions `CTRL-o` and `CTRL-i` to move back
|
123
137
|
and forth in your jump history. See `:help jump-motions` for more on
|
@@ -158,12 +172,22 @@ in Vim insert mode to invoke it.
|
|
158
172
|
|
159
173
|
## Wiki refactoring
|
160
174
|
|
161
|
-
You can
|
162
|
-
|
163
|
-
|
164
|
-
|
175
|
+
You can delete the current page with `:SWDelete` (shortcut: `:SWD`).
|
176
|
+
|
177
|
+
`:SWRenameTo [new name]` renames the current page. Make sure the new name
|
178
|
+
is valid CamelCase. You can put a namespace in front of the new name
|
179
|
+
as `namespace.` or `namespace/`. If you omit the namespace, the current
|
180
|
+
namespace is assumed.
|
181
|
+
|
182
|
+
When you rename a page, SoyWiki will update all the links on other pages
|
183
|
+
in your wiki that need to be updated in light of the change. (You'll see
|
184
|
+
the other links that were updated in the output.)
|
165
185
|
|
166
|
-
|
186
|
+
To create a wiki page directly, without first typing a WikiWord and
|
187
|
+
traversing it, type `:SWCreate` followed by the full path to the new
|
188
|
+
page. The form of the argument here should be `namespace/WikiWord`. You
|
189
|
+
may use command line file path autocomplete to fill out the namespace
|
190
|
+
subdirectory if it already exists.
|
167
191
|
|
168
192
|
Beyond the standard cut and paste, SoyWiki gives you four fast ways of
|
169
193
|
shuttling text from one wiki page to another.
|
@@ -190,27 +214,36 @@ You can use these shortcuts:
|
|
190
214
|
* `:SWInsert` → `:SWI`
|
191
215
|
* `:SWAppend` → `:SWA`
|
192
216
|
|
193
|
-
With `:SWLinkInsert` and `:SWLinkAppend` you can use
|
194
|
-
to avoid typing out the whole command name.
|
217
|
+
With `:SWLinkInsert` and `:SWLinkAppend` you can use Vim's command line
|
218
|
+
completion (`:help cmdline-completion`) to avoid typing out the whole command name.
|
219
|
+
|
220
|
+
Also, you can use Vim's command line history (`:help cmdline-history`)
|
221
|
+
and command line window (`:help cmdline-window`) to save keystrokes when
|
222
|
+
you want to repeatedly execute an insert or append command targeting the
|
223
|
+
same wiki page.
|
195
224
|
|
196
225
|
|
197
226
|
## Search
|
198
227
|
|
199
228
|
To search your SoyWiki wiki, type `:SWSearch [search term]`. Vim will
|
200
229
|
load any matches in the quickfix list window. If there are matches, you
|
201
|
-
can use `:cn` and `:cp` to go from match to match
|
202
|
-
|
230
|
+
can use `:cn` and `:cp` to go from match to match, `:cl` to list the
|
231
|
+
matches, and `:cc [item number]` to see a particular match ln the list. See
|
232
|
+
`:help quickfix` to see the list of matches. for more QuickFix commands.
|
203
233
|
|
204
|
-
Searches are case-
|
205
|
-
add a `\
|
234
|
+
Searches are case-sensitve by default. To do a case-insensitive search,
|
235
|
+
add a `\c` to your search string, e.g.:
|
206
236
|
|
207
|
-
:SWSearch Gnu\
|
237
|
+
:SWSearch Gnu\c
|
208
238
|
|
209
239
|
Again, you can use `:SWS` as a shortcut.
|
210
240
|
|
211
241
|
Under the hood, `:SWSearch` is just a thin wrapper around the `:vimgrep`
|
212
242
|
command.
|
213
243
|
|
244
|
+
Tip: You can flag important notes in your wiki content by typing flags
|
245
|
+
like TODO or IMPORTANT on the same line, and then use `:SWSearch` and
|
246
|
+
`:cl` to see all instances of them across your entire wiki.
|
214
247
|
|
215
248
|
## Revision history and distributed workflows
|
216
249
|
|
@@ -237,6 +270,14 @@ the general instructions [here][git-sync].
|
|
237
270
|
|
238
271
|
[git-sync]:http://www-cs-students.stanford.edu/~blynn/gitmagic/ch03.html
|
239
272
|
|
273
|
+
If you want to edit a common SoyWiki with many other people, it's
|
274
|
+
probably best to set up a common upstream Git repository and to work
|
275
|
+
locally on a development branch before pulling the HEAD of the master
|
276
|
+
branch from origin, merging your edits into it, and pushing the merged
|
277
|
+
result back to origin. This process may be intimidating for
|
278
|
+
non-programmers, so a future version of SoyWiki may provide a more
|
279
|
+
user-friendly interface for distributed collaboration workflows.
|
280
|
+
|
240
281
|
|
241
282
|
## Namespaced WikiWords
|
242
283
|
|
@@ -306,6 +347,18 @@ other wiki pages that include the real content. And since expansion is
|
|
306
347
|
recursive, you can effectively nest outlines within outlines, like
|
307
348
|
dreams within dreams.
|
308
349
|
|
350
|
+
|
351
|
+
## Extra macros
|
352
|
+
|
353
|
+
SoyWiki adds a few convenient Vim macros that you can use anytime.
|
354
|
+
|
355
|
+
|
356
|
+
* The `\` key in normal mode reformat the current paragraph. It is equivalent to
|
357
|
+
`gwap`. (`:help formatting`)
|
358
|
+
* `,-` inserts a long dashed line
|
359
|
+
* `,d` inserts the current date and time
|
360
|
+
|
361
|
+
|
309
362
|
## Getting help
|
310
363
|
|
311
364
|
Typing `,?` will open the help webpage in a browser.
|
data/bin/soywiki-expand
CHANGED
@@ -3,14 +3,17 @@ require 'soywiki'
|
|
3
3
|
|
4
4
|
# Takes any wiki link that stands alone on a line and expands it
|
5
5
|
|
6
|
-
|
6
|
+
# this is different from Soywiki::WIKI_WORD in that it requires ^\s* before the
|
7
|
+
# first letter
|
8
|
+
|
9
|
+
WIKI_LINK_PATTERN = /^\s*([a-z]\w+\.)?[A-Z][a-z]+[A-Z]\w*/
|
7
10
|
|
8
11
|
PROCESSED_FILES = []
|
9
12
|
|
10
13
|
def indent(text, level, mode)
|
11
14
|
return text if mode == 'seamless'
|
12
15
|
return text if level == 0
|
13
|
-
(':
|
16
|
+
(':' * level) + ' ' + text
|
14
17
|
|
15
18
|
end
|
16
19
|
|
data/bin/soywiki-ls-t
CHANGED
@@ -1,10 +1,12 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
require 'soywiki'
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
4
|
+
# this emulates ls -t in unix, but searches subdirs and returns a flat list of
|
5
|
+
# files
|
6
|
+
|
7
|
+
xs = Dir.glob('*/*').
|
8
|
+
select {|x| File.file?(x) && x.gsub('/', '.') =~ Soywiki::WIKI_WORD }.
|
9
|
+
sort_by {|x| File.stat(x).mtime }.
|
10
|
+
reverse.map {|x| x.to_page_title }
|
11
|
+
|
10
12
|
puts xs.join("\n")
|
@@ -2,29 +2,25 @@
|
|
2
2
|
# encoding: utf-8
|
3
3
|
require 'soywiki'
|
4
4
|
|
5
|
-
def
|
5
|
+
def contains_links_to?(file, page_title)
|
6
6
|
return false unless File.file?(file)
|
7
7
|
return false if (file =~ /(\.swo|\.swp)$/ || file =~ /^\./)
|
8
8
|
body = File.read(file)
|
9
|
+
# '.' must be escaped in the regular expression to match literal
|
9
10
|
body =~ /[\A\s\n\b]#{page_title.gsub(".", "\.")}\b/
|
10
11
|
end
|
11
12
|
|
12
|
-
target_page = ARGV.first
|
13
|
+
target_page = ARGV.first.dup
|
14
|
+
# make sure this is a title, not a path
|
15
|
+
target_page.gsub!("/", ".")
|
13
16
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
inbound_links_to?(file, target_page)
|
22
|
-
end
|
23
|
-
(xs + ys).uniq.sort.
|
24
|
-
each {|x| puts x.to_page_title}
|
25
|
-
else
|
26
|
-
Dir.glob(File.join("**", '*')).select do |file|
|
27
|
-
inbound_links_to?(file, target_page)
|
28
|
-
end.
|
29
|
-
each {|file| puts file.to_page_title}
|
17
|
+
|
18
|
+
# find all files in this namespace
|
19
|
+
xs = Dir.glob("#{target_page.namespace}/*").select do |file|
|
20
|
+
contains_links_to?(file, target_page) || contains_links_to?(file, target_page.short_page_title)
|
21
|
+
end
|
22
|
+
ys = Dir.glob('*/*').select do |file|
|
23
|
+
contains_links_to?(file, target_page)
|
30
24
|
end
|
25
|
+
(xs + ys).uniq.sort.each {|x| puts x.to_page_title}
|
26
|
+
|
data/bin/soywiki-rename
CHANGED
@@ -3,7 +3,6 @@ require 'soywiki'
|
|
3
3
|
|
4
4
|
oldname, newname = *ARGV
|
5
5
|
|
6
|
-
|
7
6
|
MEMO = ["Updating inbound and outbound links..."]
|
8
7
|
|
9
8
|
def report(file, oldname, newname)
|
@@ -15,78 +14,69 @@ def change_all_absolute_links(oldname, newname)
|
|
15
14
|
target_files = `grep -rlF '#{oldname.to_page_title}' *`.strip.split(/\n/)
|
16
15
|
target_files.each do |file|
|
17
16
|
text = File.read(file)
|
18
|
-
|
17
|
+
regex = /\b#{oldname.to_page_title}\b/
|
18
|
+
matches = text.scan(regex)
|
19
|
+
text.gsub!(regex, newname.to_page_title)
|
19
20
|
File.open(file, 'w') {|f| f.puts text}
|
20
21
|
report file, oldname.to_page_title, newname.to_page_title
|
21
22
|
end
|
22
23
|
end
|
23
24
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
#
|
28
|
-
# In the directory for OldName's namespace, change all referenecs to
|
29
|
-
# .OldName to .NewName
|
30
|
-
|
31
|
-
if oldname.namespaced? && (oldname.namespace == newname.namespace)
|
32
|
-
MEMO << "- Updating relative links in same namespace"
|
33
|
-
target_files = `grep -rlF '#{oldname.short_page_title}' #{oldname.namespace}/*`.strip.split(/\n/)
|
34
|
-
target_files.each do |file|
|
35
|
-
text = File.read(file)
|
36
|
-
text.gsub!(/([\b\s\n]\.)(#{oldname.short_page_title})\b/, '\1' + newname.short_page_title)
|
37
|
-
File.open(file, 'w') {|f| f.puts text}
|
38
|
-
report file, oldname.short_page_title, newname.short_page_title
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
# newname can be absolutized or top level or relative
|
43
|
-
def change_relative_inbound_links(oldname, newname)
|
44
|
-
MEMO << "- Updating relative inbound links"
|
45
|
-
target_files = `grep -rlF '#{oldname.to_page_title}' #{oldname.namespace}/*`.strip.split(/\n/)
|
25
|
+
def change_unqualified_inbound_links_in_same_namespace(oldname, newname)
|
26
|
+
MEMO << "- Updating unqualified inbound links"
|
27
|
+
target_files = `grep -rlF '[^.]#{oldname.short_page_title}' #{oldname.namespace}/*`.strip.split(/\n/)
|
46
28
|
target_files.each do |file|
|
47
29
|
text = File.read(file)
|
48
|
-
text.gsub!(/
|
30
|
+
text.gsub!(/(\A|\s)#{oldname.short_page_title}\b/, "." + newname)
|
49
31
|
File.open(file, 'w') {|f| f.puts text}
|
50
32
|
report file, oldname.short_page_title, newname
|
51
33
|
end
|
52
34
|
end
|
53
35
|
|
54
|
-
RELATIVE_LINK_REGEX =/(
|
36
|
+
RELATIVE_LINK_REGEX =/(\A\s)([A-Z][a-z]+[A-Z]\w*)/
|
55
37
|
|
56
|
-
def
|
57
|
-
MEMO << "Absolutizing
|
58
|
-
|
59
|
-
|
38
|
+
def absolutize_unqualified_outbound_links(oldname, newname)
|
39
|
+
MEMO << "Absolutizing unqualified inbound links"
|
40
|
+
target_file = newname.to_file_path
|
41
|
+
if File.exist?(target_file)
|
42
|
+
text = File.read(target_file)
|
60
43
|
matches = text.scan(RELATIVE_LINK_REGEX)
|
61
|
-
text.gsub!(RELATIVE_LINK_REGEX,
|
62
|
-
File.open(
|
63
|
-
MEMO << " - In file #{
|
44
|
+
text.gsub!(RELATIVE_LINK_REGEX, oldname.namespace + '.\1')
|
45
|
+
File.open(target_file, 'w') {|f| f.puts text}
|
46
|
+
MEMO << " - In file #{target_file}: Absolutized these unqualified links: #{matches.inspect}"
|
64
47
|
end
|
65
48
|
end
|
66
49
|
|
67
50
|
|
68
|
-
#
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
51
|
+
# Three other cases to cover, involving namespaces:
|
52
|
+
#
|
53
|
+
# Case 1: newname is in same namespace as oldname
|
54
|
+
#
|
55
|
+
# In the directory for OldName's namespace, change all unqualified referenecs to
|
56
|
+
# OldName to NewName
|
57
|
+
|
58
|
+
if oldname.namespace == newname.namespace
|
59
|
+
MEMO << "- Updating unqualified links in same namespace"
|
60
|
+
target_files = `grep -rlF '#{oldname.short_page_title}' #{oldname.namespace}/*`.strip.split(/\n/)
|
61
|
+
target_files.each do |file|
|
62
|
+
text = File.read(file)
|
63
|
+
text.gsub!(/(\A\s)(#{oldname.short_page_title})\b/, newname.short_page_title)
|
64
|
+
File.open(file, 'w') {|f| f.puts text}
|
65
|
+
report file, oldname.short_page_title, newname.short_page_title
|
66
|
+
end
|
76
67
|
end
|
77
68
|
|
78
|
-
# Case
|
79
|
-
if oldname.
|
80
|
-
# In the directory for OldName's namespace, change all references to
|
81
|
-
#
|
82
|
-
|
83
|
-
# And in the renamed file, change all
|
84
|
-
#
|
85
|
-
|
69
|
+
# Case 2: newname is in different namespace from oldname
|
70
|
+
if oldname.namespace != newname.namespace
|
71
|
+
# In the directory for OldName's namespace, change all unqualified references to
|
72
|
+
# OldName to newnamespace.NewName (i.e. NewName).
|
73
|
+
change_unqualified_inbound_links_in_same_namespace(oldname, newname)
|
74
|
+
# And in the renamed file, change all unqualified references to
|
75
|
+
# PageName to oldnamespace.PageName
|
76
|
+
absolutize_unqualified_outbound_links(oldname, newname)
|
86
77
|
end
|
87
78
|
|
88
79
|
# Finally,
|
89
|
-
|
90
80
|
change_all_absolute_links oldname, newname
|
91
81
|
|
92
82
|
puts MEMO.join("\n")
|
data/lib/soywiki.rb
CHANGED
@@ -1,11 +1,5 @@
|
|
1
1
|
|
2
2
|
class String
|
3
|
-
def is_namespaced?
|
4
|
-
self.split(/\.|\//).size == 2
|
5
|
-
end
|
6
|
-
|
7
|
-
alias :namespaced? :is_namespaced?
|
8
|
-
|
9
3
|
# TODO change this to a Windows compatible approach
|
10
4
|
def to_file_path
|
11
5
|
self.gsub(".", "/")
|
@@ -20,15 +14,14 @@ class String
|
|
20
14
|
end
|
21
15
|
|
22
16
|
def namespace
|
23
|
-
return nil unless self.namespaced?
|
24
17
|
self.to_page_title.split('.')[0]
|
25
18
|
end
|
26
19
|
end
|
27
20
|
|
28
21
|
|
29
22
|
module Soywiki
|
30
|
-
VERSION = '0.
|
31
|
-
WIKI_WORD = /\b([a-z][\w_]+\.)?[A-Z][a-z]+[A-Z]\w*\b
|
23
|
+
VERSION = '0.1.1'
|
24
|
+
WIKI_WORD = /\b([a-z][\w_]+\.)?[A-Z][a-z]+[A-Z]\w*\b/
|
32
25
|
|
33
26
|
def self.run
|
34
27
|
if %W( -v --version -h --help).include?(ARGV.first)
|