/
viki.vim
2993 lines (2779 loc) · 105 KB
/
viki.vim
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
" Viki.vim -- A pseudo mini-wiki minor mode for Vim
" @Author: Thomas Link (samul AT web.de)
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
" @Created: 08-Dec-2003.
" @Last Change: 2007-06-24.
" @Revision: 2.2.2126
"
" GetLatestVimScripts: 861 1 viki.vim
"
" Short Description:
" This plugin adds wiki-like hypertext capabilities to any document. Just
" type :VikiMinorMode and all wiki names will be highlighted. If you press
" <c-cr> when the cursor is over a wiki name, you jump to (or create) the
" referred page. When invoked as :VikiMode or via :set ft=viki additional
" highlighting is provided.
"
" Requirements:
" - tlib.vim
"
" Optional Enhancements:
" - imaps.vim (vimscript #244 or #475 for |:VimQuote|)
" - kpsewhich (not a vim plugin :-) for vikiLaTeX
"
" TODO:
" - cache inexistent patterns (check for file atime & size)
" - VikiEdit completion for names containing blanks
" - File names containing #
" - Per Interviki simple name patterns
" - Allow Wiki links like ::Word or even ::word (not in minor mode due
" possible conflict with various programming languages?)
" - New region: file listing (auto-generate/update a file listing; i.e. the
" region content is automatically generated when opening a file or so)
" - :VikiRename command: rename links/files (requires a cross-plattform grep
" or similar; maybe 7.0)
" - don't know how to deal with viki names that span several lines (e.g. in
" LaTeX mode)
"
" Change Log: (See bottom of file)
if &cp || exists("loaded_viki") "{{{2
finish
endif
if !exists('loaded_tlib') || loaded_tlib < 8
echoerr 'tlib >= 0.8 is required'
finish
endif
let loaded_viki = 202
" This is what we consider nil, in the absence of nil in vimscript
let g:vikiDefNil = ''
" In a previous version this was used as list separator and as nil too
let g:vikiDefSep = "\n"
" let s:vikiSelfEsc = '\'
" In extended viki links this is considered as a reference to the current
" document. This is likely to go away.
let g:vikiSelfRef = '.'
" let s:vikiEnabledID = loaded_viki .'_'. strftime('%c')
" Configuration {{{1
" If zero, viki is disabled, though the code is loaded.
if !exists("g:vikiEnabled") "{{{2
let g:vikiEnabled = 1
endif
" Support for the taglist plugin.
if !exists("tlist_viki_settings") "{{{2
let tlist_viki_settings="deplate;s:structure"
endif
" A simple viki name is made from a series of upper and lower characters
" (i.e. CamelCase-names). These two variables define what is considered as
" upper and lower-case characters. We don't rely on the builtin
" functionality for this.
if !exists("g:vikiUpperCharacters") "{{{2
let g:vikiUpperCharacters = "A-Z"
endif
if !exists("g:vikiLowerCharacters") "{{{2
let g:vikiLowerCharacters = "a-z"
endif
" The prefix for the menu of intervikis. Set to '' in order to remove the
" menu.
if !exists("g:vikiMenuPrefix") "{{{2
let g:vikiMenuPrefix = "Plugin.Viki."
endif
" URLs matching these protocols are handled by VikiOpenSpecialProtocol()
if !exists("g:vikiSpecialProtocols") "{{{2
let g:vikiSpecialProtocols = 'https\?\|ftps\?\|nntp\|mailto\|mailbox\|file'
endif
" Exceptions from g:vikiSpecialProtocols
if !exists("g:vikiSpecialProtocolsExceptions") "{{{2
let g:vikiSpecialProtocolsExceptions = ""
endif
" Files matching these suffixes are handled by VikiOpenSpecialFile()
if !exists("g:vikiSpecialFiles") "{{{2
let g:vikiSpecialFiles = [
\ 'aac',
\ 'aif',
\ 'aiff',
\ 'au',
\ 'avi',
\ 'bmp',
\ 'doc',
\ 'dvi',
\ 'eps',
\ 'eps',
\ 'gif',
\ 'htm',
\ 'html',
\ 'jpeg',
\ 'jpg',
\ 'm3u',
\ 'mp1',
\ 'mp2',
\ 'mp3',
\ 'mp4',
\ 'mpeg',
\ 'mpg',
\ 'odg',
\ 'ods',
\ 'odt',
\ 'ogg',
\ 'pdf',
\ 'png',
\ 'ppt',
\ 'ps',
\ 'rtf',
\ 'voc',
\ 'wav',
\ 'wma',
\ 'wmf',
\ 'wmv',
\ 'xhtml',
\ 'xls',
\ ]
endif
" Exceptions from g:vikiSpecialFiles
if !exists("g:vikiSpecialFilesExceptions") "{{{2
let g:vikiSpecialFilesExceptions = ""
endif
" Return the color name for hyper links
function! VikiHyperLinkColor() "{{{3
if exists("g:vikiHyperLinkColor")
return g:vikiHyperLinkColor
elseif &background == "light"
return "DarkBlue"
else
return "LightBlue"
endif
endf
" Return the color name for inexistent links
function! VikiInexistentColor() "{{{3
if exists("g:vikiInexistentColor")
return g:vikiInexistentColor
elseif &background == "light"
return "DarkRed"
else
return "Red"
endif
endf
" If non-nil, use the parent document's suffix.
if !exists("g:vikiUseParentSuffix") | let g:vikiUseParentSuffix = 0 | endif "{{{2
" Default file suffix.
if !exists("g:vikiNameSuffix") | let g:vikiNameSuffix = "" | endif "{{{2
" Prefix for anchors
if !exists("g:vikiAnchorMarker") | let g:vikiAnchorMarker = "#" | endif "{{{2
" If non-nil, search anchors anywhere in the text too (without special
" markup)
if !exists("g:vikiFreeMarker") | let g:vikiFreeMarker = 0 | endif "{{{2
" List of enabled viki name types
if !exists("g:vikiNameTypes") | let g:vikiNameTypes = "csSeuixwf" | endif "{{{2
" Which directory explorer to use to edit directories
if !exists("g:vikiExplorer") | let g:vikiExplorer = "Sexplore" | endif "{{{2
" If hide or update: use the respective command when leaving a buffer
if !exists("g:vikiHide") | let g:vikiHide = '' | endif "{{{2
" Don't use g:vikiHide for commands matching this rx
if !exists("g:vikiNoWrapper") | let g:vikiNoWrapper = '\cexplore' | endif "{{{2
" Cache information about a document's inexistent names
if !exists("g:vikiCacheInexistent") | let g:vikiCacheInexistent = 1 | endif "{{{2
" Mark up inexistent names.
if !exists("g:vikiMarkInexistent") | let g:vikiMarkInexistent = 1 | endif "{{{2
" If non-nil, map keys that trigger the evaluation of inexistent names
if !exists("g:vikiMapInexistent") | let g:vikiMapInexistent = 1 | endif "{{{2
" Map these keys for g:vikiMapInexistent to LineQuick
if !exists("g:vikiMapKeys") | let g:vikiMapKeys = "]).,;:!?\"' " | endif "{{{2
" Map these keys for g:vikiMapInexistent to ParagraphVisible
if !exists("g:vikiMapQParaKeys") | let g:vikiMapQParaKeys = "\n" | endif "{{{2
" Check the viki name before inserting this character
if !exists("g:vikiMapBeforeKeys") | let g:vikiMapBeforeKeys = ']' | endif "{{{2
" Some functions a gathered in families/classes. See vikiLatex.vim for
" an example.
if !exists("g:vikiFamily") | let g:vikiFamily = "" | endif "{{{2
" The directory separator
if !exists("g:vikiDirSeparator") | let g:vikiDirSeparator = "/" | endif "{{{2
" The version of Deplate markup
if !exists("g:vikiTextstylesVer") | let g:vikiTextstylesVer = 2 | endif "{{{2
" if !exists("g:vikiBasicSyntax") | let g:vikiBasicSyntax = 0 | endif "{{{2
" If non-nil, display headings of different levels in different colors
if !exists("g:vikiFancyHeadings") | let g:vikiFancyHeadings = 0 | endif "{{{2
" Consider fold levels bigger that this as text body, levels smaller
" than this as headings
if !exists("g:vikiFoldBodyLevel") | let g:vikiFoldBodyLevel = 5 | endif "{{{2
" The default viki page (as absolute filename)
if !exists("g:vikiHomePage") | let g:vikiHomePage = '' | endif "{{{2
" What is considered for folding
if !exists("g:vikiFolds") | let g:vikiFolds = 'hf' | endif "{{{2
" The default filename for an interviki's index name
if !exists("g:vikiIndex") | let g:vikiIndex = 'index' | endif "{{{2
" How often the feedback is changed when marking inexisting links
if !exists("g:vikiFeedbackMin") | let g:vikiFeedbackMin = &lines | endif "{{{2
" The map leader for most viki key maps.
if !exists("g:vikiMapLeader") | let g:vikiMapLeader = '<LocalLeader>v' | endif "{{{2
" If non-nil, anchors like #mX are turned into vim marks
if !exists("g:vikiAutoMarks") | let g:vikiAutoMarks = 1 | endif "{{{2
" if !exists("g:vikiOpenInWindow") | let g:vikiOpenInWindow = '' | endif "{{{2
if !exists("g:vikiHighlightMath") | let g:vikiHighlightMath = '' | endif "{{{2
" If non-nil, cache back-links information
if !exists("g:vikiSaveHistory") | let g:vikiSaveHistory = 0 | endif "{{{2
" The variable that keeps back-links information
if !exists("g:VIKIBACKREFS") | let g:VIKIBACKREFS = {} | endif "{{{2
" A list of files that contain special viki names
if v:version >= 700 && !exists("g:vikiHyperWordsFiles") "{{{2
let g:vikiHyperWordsFiles = [
\ './.vikiWords',
\ get(split(&rtp, ','), 0).'/vikiWords.txt'
\ ]
endif
" Define which keys to map
if !exists("g:vikiMapFunctionality") "{{{2
" b ... go back
" c ... follow link (c-cr)
" e ... edit
" F ... find
" f ... follow link (<LocalLeader>v)
" i ... check for inexistant destinations
" I ... map keys in g:vikiMapKeys and g:vikiMapQParaKeys
" m[fb] ... map mouse (depends on f or b)
" p ... edit parent (or backlink)
" q ... quote
" tF ... tab as find
" Files ... #Files related
" let g:vikiMapFunctionality = 'mf mb tF c q e i I Files'
let g:vikiMapFunctionality = 'ALL'
endif
" Define which keys to map in minor mode (invoked via :VikiMinorMode)
if !exists("g:vikiMapFunctionalityMinor") "{{{2
let g:vikiMapFunctionalityMinor = 'f b p mf mb tF c q e i'
endif
" Special file handlers {{{1
if !exists('g:vikiOpenFileWith_ws') && exists(':WsOpen') "{{{2
function! s:OpenAsWorkspace(file)
exec 'WsOpen '. escape(a:file, ' &!%')
exec 'lcd '. escape(fnamemodify(a:file, ':p:h'), ' &!%')
endf
let g:vikiOpenFileWith_ws = "call <SID>OpenAsWorkspace('%{FILE}')"
call add(g:vikiSpecialFiles, 'ws')
endif
if type(g:vikiSpecialFiles) != 3
echoerr 'Viki: g:vikiSpecialFiles must be a list'
endif
" TAssert IsList(g:vikiSpecialFiles)
if !exists("g:vikiOpenFileWith_ANY") "{{{2
if exists('g:netrw_browsex_viewer')
let g:vikiOpenFileWith_ANY = "exec 'silent !'. g:netrw_browsex_viewer .' '. escape('%{FILE}', ' &!%')"
elseif has("win32") || has("win16") || has("win64")
let g:vikiOpenFileWith_ANY = "exec 'silent !cmd /c start '. escape('%{FILE}', ' &!%')"
elseif $GNOME_DESKTOP_SESSION_ID != ""
let g:vikiOpenFileWith_ANY = "exec 'silent !gnome-open '. escape('%{FILE}', ' &!%')"
elseif $KDEDIR != ""
let g:vikiOpenFileWith_ANY = "exec 'silent !kfmclient exec '. escape('%{FILE}', ' &!%')"
endif
endif
if !exists('*VikiOpenSpecialFile') "{{{2
function! VikiOpenSpecialFile(file) "{{{3
" let proto = tolower(matchstr(a:file, '\c\.\zs[a-z]\+$'))
let proto = tolower(fnamemodify(a:file, ':e'))
if exists('g:vikiOpenFileWith_'. proto)
let prot = g:vikiOpenFileWith_{proto}
elseif exists('g:vikiOpenFileWith_ANY')
let prot = g:vikiOpenFileWith_ANY
else
let prot = ''
endif
if prot != ''
let openFile = VikiSubstituteArgs(prot, 'FILE', a:file)
exec openFile
else
throw 'Viki: Please define g:vikiOpenFileWith_'. proto .' or g:vikiOpenFileWith_ANY!'
endif
endf
endif
" Special protocol handlers {{{1
if !exists('g:vikiOpenUrlWith_mailbox') "{{{2
let g:vikiOpenUrlWith_mailbox="call VikiOpenMailbox('%{URL}')"
function! VikiOpenMailbox(url) "{{{3
exec VikiDecomposeUrl(strpart(a:url, 10))
let idx = matchstr(args, 'number=\zs\d\+$')
if filereadable(filename)
call VikiOpenLink(filename, '', 0, 'go '.idx)
else
throw 'Viki: Can't find mailbox url: '.filename
endif
endf
endif
" Possible values: special*, query, normal
if !exists("g:vikiUrlFileAs") | let g:vikiUrlFileAs = 'special' | endif "{{{2
if !exists("g:vikiOpenUrlWith_file") "{{{2
let g:vikiOpenUrlWith_file="call VikiOpenFileUrl('%{URL}')"
function! VikiOpenFileUrl(url) "{{{3
if VikiIsSpecialFile(a:url)
if g:vikiUrlFileAs == 'special'
let as_special = 1
elseif g:vikiUrlFileAs == 'query'
echo a:url
let as_special = input('Treat URL as special file? (Y/n) ')
let as_special = (as_special[0] !=? 'n')
else
let as_special = 0
endif
if as_special
call VikiOpenSpecialFile(a:url)
return
endif
endif
exec VikiDecomposeUrl(strpart(a:url, 7))
if filereadable(filename)
call VikiOpenLink(filename, anchor)
else
throw 'Viki: Can't find file url: '.filename
endif
endf
endif
if !exists("g:vikiOpenUrlWith_ANY") "{{{2
" let g:vikiOpenUrlWith_ANY = "exec 'silent !". g:netrw_browsex_viewer ." '. escape('%{URL}', ' &!%')"
if has("win32")
let g:vikiOpenUrlWith_ANY = "exec 'silent !rundll32 url.dll,FileProtocolHandler '. escape('%{URL}', ' !&%')"
elseif $GNOME_DESKTOP_SESSION_ID != ""
let g:vikiOpenUrlWith_ANY = "exec 'silent !gnome-open '. escape('%{URL}', ' !&%')"
elseif $KDEDIR != ""
let g:vikiOpenUrlWith_ANY = "exec 'silent !kfmclient exec '. escape('%{URL}', ' !&%')"
endif
endif
if !exists("*VikiOpenSpecialProtocol") "{{{2
function! VikiOpenSpecialProtocol(url) "{{{3
let proto = tolower(matchstr(a:url, '\c^[a-z]\{-}\ze:'))
let prot = 'g:vikiOpenUrlWith_'. proto
let protp = exists(prot)
if !protp
let prot = 'g:vikiOpenUrlWith_ANY'
let protp = exists(prot)
endif
if protp
exec 'let openURL = '. prot
let openURL = VikiSubstituteArgs(openURL, 'URL', a:url)
" TLogVAR openURL
exec openURL
else
throw 'Viki: Please define g:vikiOpenUrlWith_'. proto .' or g:vikiOpenUrlWith_ANY!'
endif
endf
endif
" Functions {{{1
" Outdated way to keep cursor information
function! s:ResetSavedCursorPosition() "{{{3
let s:cursorSet = -1
let s:cursorCol = -1
let s:cursorVCol = -1
let s:cursorLine = -1
let s:cursorWinTLine = -1
let s:cursorEol = 0
let s:lazyredraw = &lazyredraw
endf
call s:ResetSavedCursorPosition()
" Outdated: a cheap implementation of printf
function! s:sprintf1(string, arg) "{{{3
if exists('printf')
return printf(string, a:arg)
else
let rv = substitute(a:string, '\C[^%]\zs%s', escape(a:arg, '"\'), 'g')
let rv = substitute(rv, '%%', '%', 'g')
return rv
end
endf
let s:InterVikiRx = '^\(['. g:vikiUpperCharacters .']\+\)::\(.*\)$'
let s:InterVikis = []
" Define an interviki name
" VikiDefine(name, prefix, ?suffix="*", ?index="Index.${suffix}")
" suffix == "*" -> g:vikiNameSuffix
function! VikiDefine(name, prefix, ...) "{{{3
if a:name =~ '[^A-Z]'
throw 'Invalid interviki name: '. a:name
endif
call add(s:InterVikis, a:name .'::')
call sort(s:InterVikis)
let g:vikiInter{a:name} = a:prefix
let g:vikiInter{a:name}_suffix = a:0 >= 1 && a:1 != '*' ? a:1 : g:vikiNameSuffix
let index = a:0 >= 2 && a:2 != '' ? a:2 : g:vikiIndex
let findex = fnamemodify(g:vikiInter{a:name} .'/'. index . g:vikiInter{a:name}_suffix, ':p')
if filereadable(findex)
let vname = VikiMakeName(a:name, index, 0)
let g:vikiInter{a:name}_index = index
else
" let vname = '[['. a:name .'::]]'
let vname = a:name .'::'
end
let vname = escape(vname, ' \%#')
exec 'command! '. a:name .' VikiEdit! '. vname
if g:vikiMenuPrefix != ''
exec 'amenu '. g:vikiMenuPrefix . a:name .' :VikiEdit! '. vname .'<cr>'
endif
endf
command! -nargs=+ VikiDefine call VikiDefine(<f-args>)
if g:vikiMenuPrefix != '' "{{{2
exec 'amenu '. g:vikiMenuPrefix .'Home :VikiHome<cr>'
exec 'amenu '. g:vikiMenuPrefix .'-SepViki1- :'
endif
function! s:AddToRegexp(regexp, pattern) "{{{3
if a:pattern == ''
return a:regexp
elseif a:regexp == ''
return a:pattern
else
return a:regexp .'\|'. a:pattern
endif
endf
" Make all filenames use slashes
function! s:CanonicFilename(fname) "{{{3
return substitute(simplify(a:fname), '[\/]\+', '/', 'g')
endf
" Build the rx to find viki names
function! s:VikiFindRx() "{{{3
let rx = s:AddToRegexp('', b:vikiSimpleNameSimpleRx)
let rx = s:AddToRegexp(rx, b:vikiExtendedNameSimpleRx)
let rx = s:AddToRegexp(rx, b:vikiUrlSimpleRx)
return rx
endf
" Wrap edit commands. Every action that creates a new buffer should use
" this function.
function! s:EditWrapper(cmd, fname) "{{{3
" TLogVAR a:cmd, a:fname
let fname = escape(simplify(a:fname), ' %#')
" let fname = escape(simplify(a:fname), '%#')
if a:cmd =~ g:vikiNoWrapper
exec a:cmd .' '. fname
else
try
if g:vikiHide == 'hide'
exec 'hide '. a:cmd .' '. fname
elseif g:vikiHide == 'update'
update
exec a:cmd .' '. fname
else
exec a:cmd .' '. fname
endif
catch /^Vim\%((\a\+)\)\=:E37/
echoerr "Vim raised E37: You tried to abondon a dirty buffer (see :h E37)"
echoerr "Viki: You may want to reconsider your g:vikiHide or 'hidden' settings"
catch /^Vim\%((\a\+)\)\=:E325/
endtry
endif
endf
" Find a viki name
" VikiFind(flag, ?count=0, ?rx=nil)
function! VikiFind(flag, ...) "{{{3
let rx = (a:0 >= 2 && a:2 != '') ? a:2 : s:VikiFindRx()
if rx != ""
let i = a:0 >= 1 ? a:1 : 0
while i >= 0
call search(rx, a:flag)
let i = i - 1
endwh
endif
endf
command! -count VikiFindNext call VikiDispatchOnFamily('VikiFind', '', '', <count>)
command! -count VikiFindPrev call VikiDispatchOnFamily('VikiFind', '', 'b', <count>)
" Find the previous heading
function! VikiFindPrevHeading()
let vikisr=@/
let cl = getline('.')
if cl =~ '^\*'
let head = matchstr(cl, '^\*\+')
let head = '*\{1,'. len(head) .'}'
else
let head = '*\+'
endif
call search('\V\^'. head .'\s', 'bW')
let @/=vikisr
endf
" Find the next heading
function! VikiFindNextHeading()
let pos = getpos('.')
" TLogVAR pos
let cl = getline('.')
" TLogDBG 'line0='. cl
if cl =~ '^\*'
let head = matchstr(cl, '^\*\+')
let head = '*\{1,'. len(head) .'}'
else
let head = '*\+'
endif
" TLogDBG 'head='. head
" TLogVAR pos
call setpos('.', pos)
let vikisr = @/
call search('\V\^'. head .'\s', 'W')
let @/=vikisr
endf
" Test whether we want to markup a certain viki name type for the current
" buffer
" s:IsSupportedType(type, ?types=b:vikiNameTypes)
function! s:IsSupportedType(type, ...) "{{{3
if a:0 >= 1
let types = a:1
elseif exists('b:vikiNameTypes')
let types = b:vikiNameTypes
else
let types = g:vikiNameTypes
end
if types == ''
return 1
else
" return stridx(b:vikiNameTypes, a:type) >= 0
return types =~# '['. a:type .']'
endif
endf
" Build an rx from a list of names
function! VikiRxFromCollection(coll) "{{{3
" TAssert IsList(a:coll)
let rx = join(a:coll, '\|')
if rx == ''
return ''
else
return '\V\('. rx .'\)'
endif
endf
" Mark inexistent viki names
" VikiMarkInexistent(line1, line2, ?maxcol, ?quick)
" maxcol ... check only up to maxcol
" quick ... check only if the cursor is located after a link
function! s:VikiMarkInexistent(line1, line2, ...) "{{{3
if !exists('b:vikiMarkInexistent') || !b:vikiMarkInexistent
return
endif
if s:cursorCol == -1
" let cursorRestore = 1
let li0 = line('.')
let co0 = col('.')
let co1 = co0 - 1
else
" let cursorRestore = 0
let li0 = s:cursorLine
let co0 = s:cursorCol
let co1 = co0 - 2
end
if a:0 >= 2 && a:2 > 0 && synIDattr(synID(li0, co1, 1), 'name') !~ '^viki.*Link$'
return
endif
let lazyredraw = &lazyredraw
set lazyredraw
let maxcol = a:0 >= 1 ? (a:1 == -1 ? 9999999 : a:1) : 9999999
if a:line1 > 0
keepjumps call cursor(a:line1, 1)
let min = a:line1
else
go
let min = 1
endif
let max = a:line2 > 0 ? a:line2 : line('$')
if line('.') == 1 && line('$') == max
let b:vikiNamesNull = []
let b:vikiNamesOk = []
else
if !exists('b:vikiNamesNull') | let b:vikiNamesNull = [] | endif
if !exists('b:vikiNamesOk') | let b:vikiNamesOk = [] | endif
endif
let feedback = (max - min) > b:vikiFeedbackMin
let b:vikiMarkingInexistent = 1
try
if feedback
let sl = &statusline
let rng = min .'-'. max
let &statusline='Viki: checking line '. rng
let rng = ' ('. min .'-'. max .')'
redrawstatus
endif
if line('.') == 1
keepjumps norm! G$
else
keepjumps norm! k$
endif
let rx = s:VikiFindRx()
let pp = 0
let ll = 0
let cc = 0
keepjumps let li = search(rx, 'w')
let co = col('.')
while li != 0 && !(ll == li && cc == co) && li >= min && li <= max && co <= maxcol
if synIDattr(synID(line('.'), col('.'), 1), "name") !~ '^vikiFiles'
if feedback
" if li % 10 == 0 && li != ll
if li % 10 == 0
let &statusline='Viki: checking line '. li . rng
redrawstatus
" let ll = li
endif
endif
let ll = li
let co1 = co - 1
let def = VikiGetLink(1, getline('.'), co1)
" TAssert IsList(def)
" TLogDBG getline('.')[co1 : -1]
" TLogDBG string(def)
if empty(def)
echom 'Internal error: VikiMarkInexistent: '. co .' '. getline('.')
else
exec VikiSplitDef(def)
if v_part =~ '^'. b:vikiSimpleNameSimpleRx .'$'
if v_dest =~ g:vikiSpecialProtocols
let check = 0
elseif v:version >= 700 && exists('b:vikiHyperWordTable') && has_key(b:vikiHyperWordTable, v_part)
let check = 0
else
let check = 1
let partx = escape(v_part, "'\"\\/")
if partx !~ '^\['
let partx = '\<'.partx
endif
if partx !~ '\]$'
let partx = partx.'\>'
endif
endif
elseif v_dest =~ '^'. b:vikiUrlSimpleRx .'$'
let check = 0
let partx = escape(v_part, "'\"\\/")
call filter(b:vikiNamesNull, 'v:val != partx')
call insert(b:vikiNamesOk, partx)
elseif v_part =~ b:vikiExtendedNameSimpleRx
if v_dest =~ '^'. g:vikiSpecialProtocols .':'
let check = 0
else
let check = 1
let partx = escape(v_part, "'\"\\/")
endif
" elseif v_part =~ b:vikiCmdSimpleRx
" <+TBD+>
else
let check = 0
endif
" TLogDBG "v_dest=".v_dest
" TLogDBG "check=".check
if check && v_dest != "" && v_dest != g:vikiSelfRef && !isdirectory(v_dest)
if filereadable(v_dest)
call filter(b:vikiNamesNull, 'v:val != partx')
call insert(b:vikiNamesOk, partx)
else
call insert(b:vikiNamesNull, partx)
call filter(b:vikiNamesOk, 'v:val != partx')
endif
endif
endif
endif
keepjumps let li = search(rx, 'W')
let co = col('.')
endwh
call VikiHighlightInexistent()
let b:vikiCheckInexistent = 0
finally
" if cursorRestore && !s:cursorSet
" call VikiRestoreCursorPosition(li0, co0)
" endif
if feedback
let &statusline = sl
endif
let &lazyredraw = lazyredraw
unlet! b:vikiMarkingInexistent
endtry
endf
" Actually highlight inexistent file names
function! VikiHighlightInexistent() "{{{3
if b:vikiMarkInexistent == 1
if exists('b:vikiNamesNull')
exe 'syntax clear '. b:vikiInexistentHighlight
let rx = VikiRxFromCollection(b:vikiNamesNull)
if rx != ''
exe 'syntax match '. b:vikiInexistentHighlight .' /'. rx .'/'
endif
endif
elseif b:vikiMarkInexistent == 2
if exists('b:vikiNamesOk')
syntax clear vikiOkLink
syntax clear vikiExtendedOkLink
let rx = VikiRxFromCollection(b:vikiNamesOk)
if rx != ''
exe 'syntax match vikiOkLink /'. rx .'/'
endif
endif
endif
endf
" command! -nargs=* -range=% VikiMarkInexistent
" \ call VikiSaveCursorPosition()
" \ | call <SID>VikiMarkInexistent(<line1>, <line2>, <f-args>)
" \ | call VikiRestoreCursorPosition()
" \ | call <SID>ResetSavedCursorPosition()
command! -nargs=* -range=% VikiMarkInexistent call <SID>VikiMarkInexistentInRange(<line1>, <line2>)
" Check a text element for inexistent names
if v:version == 700 && !has('patch8')
function! s:SID()
let fullname = expand("<sfile>")
return matchstr(fullname, '<SNR>\d\+_')
endf
function! VikiMarkInexistentInElement(elt) "{{{3
let lr = &lazyredraw
set lazyredraw
call VikiSaveCursorPosition()
let kpk = s:SID() . "VikiMarkInexistentIn" . a:elt
call {kpk}()
call VikiRestoreCursorPosition()
call s:ResetSavedCursorPosition()
let &lazyredraw = lr
return ''
endf
else
function! VikiMarkInexistentInElement(elt) "{{{3
let lr = &lazyredraw
set lazyredraw
" let pos = getpos('.')
" TLogVAR pos
try
call VikiSaveCursorPosition()
call s:VikiMarkInexistentIn{a:elt}()
call VikiRestoreCursorPosition()
call s:ResetSavedCursorPosition()
return ''
finally
" TLogVAR pos
" call setpos('.', pos)
let &lazyredraw = lr
endtry
endf
endif
function! s:VikiMarkInexistentInRange(line1, line2) "{{{3
let lr = &lazyredraw
set lazyredraw
" let pos = getpos('.')
" TLogVAR pos
try
call VikiSaveCursorPosition()
call s:VikiMarkInexistent(a:line1, a:line2)
call VikiRestoreCursorPosition()
call s:ResetSavedCursorPosition()
" call s:VikiMarkInexistent(a:line1, a:line2)
finally
" TLogVAR pos
" call setpos('.', pos)
let &lazyredraw = lr
endtry
endf
function! s:VikiMarkInexistentInParagraph() "{{{3
if getline('.') =~ '\S'
call s:VikiMarkInexistent(line("'{"), line("'}"))
endif
endf
function! s:VikiMarkInexistentInDocument() "{{{3
call s:VikiMarkInexistent(1, line("$"))
endf
function! s:VikiMarkInexistentInParagraphVisible() "{{{3
let l0 = max([line("'{"), line("w0")])
" let l1 = line("'}")
let l1 = line(".")
call s:VikiMarkInexistent(l0, l1)
endf
function! s:VikiMarkInexistentInParagraphQuick() "{{{3
let l0 = line("'{")
let l1 = line("'}")
call s:VikiMarkInexistent(l0, l1, -1, 1)
endf
function! s:VikiMarkInexistentInLine() "{{{3
call s:VikiMarkInexistent(line("."), line("."))
endf
function! s:VikiMarkInexistentInLineQuick() "{{{3
call s:VikiMarkInexistent(line("."), line("."), (col('.') + 1), 1)
endf
" Set values for the cache
function! s:CValsSet(cvals, var) "{{{3
if exists('b:'. a:var)
let a:cvals[a:var] = b:{a:var}
endif
endf
" First-time markup of inexistent names. Handles cached values. Called
" from syntax/viki.vim
function! VikiMarkInexistentInitial() "{{{3
if g:vikiCacheInexistent
let cfile = tlib#GetCacheName('viki_inexistent', '', 1)
" TLogVAR cfile
if !empty(cfile)
let cvals = tlib#CacheGet(cfile)
" TLogVAR cvals
if !empty(cvals)
for [key, value] in items(cvals)
let b:{key} = value
unlet value
endfor
call VikiHighlightInexistent()
return
endif
endif
else
let cfile = ''
endif
call VikiMarkInexistentInElement('Document')
if !empty(cfile)
let cvals = {}
call s:CValsSet(cvals, 'vikiNamesNull')
call s:CValsSet(cvals, 'vikiNamesOk')
call s:CValsSet(cvals, 'vikiInexistentHighlight')
call s:CValsSet(cvals, 'vikiMarkInexistent')
call tlib#CacheSave(cfile, cvals)
endif
endf
" The function called from autocommands: re-check for inexistent names
" when re-entering a buffer.
function! VikiCheckInexistent() "{{{3
if g:vikiEnabled && exists("b:vikiCheckInexistent") && b:vikiCheckInexistent > 0
call s:VikiMarkInexistentInRange(b:vikiCheckInexistent, b:vikiCheckInexistent)
endif
endf
" Initialize buffer-local variables on the basis of other variables "..."
" or from a global variable.
function! VikiSetBufferVar(name, ...) "{{{3
if !exists('b:'.a:name)
if a:0 > 0
let i = 1
while i <= a:0
exe 'let altVar = a:'. i
if altVar[0] == '*'
exe 'let b:'.a:name.' = '. strpart(altVar, 1)
return
elseif exists(altVar)
exe 'let b:'.a:name.' = '. altVar
return
endif
let i = i + 1
endwh
throw 'VikiSetBuffer: Couldn't set '. a:name
else
exe 'let b:'.a:name.' = g:'.a:name
endif
endif
endf
" Get some vimscript code to set a variable from either a buffer-local or
" a global variable
function! s:VikiLetVar(name, var) "{{{3
if exists('b:'.a:var)
return 'let '.a:name.' = b:'.a:var
elseif exists('g:'.a:var)
return 'let '.a:name.' = g:'.a:var
else
return ''
endif
endf
" Call a fn.family if existent, call fn otherwise.
" VikiDispatchOnFamily(fn, ?family='', *args)
function! VikiDispatchOnFamily(fn, ...) "{{{3
let fam = a:0 >= 1 && a:1 != '' ? a:1 : s:Family()
if fam == '' || !exists('*'.a:fn.fam)
let cmd = a:fn
else
let cmd = a:fn.fam
endif
if a:0 >= 2
let args = join(map(range(2, a:0), 'string(a:{v:val})'), ', ')
else
let args = ''
endif
" TLogDBG args
" TLogDBG cmd .'('. args .')'
exe 'return '. cmd .'('. args .')'
endf
" Prepare a buffer for use with viki.vim. Setup all buffer-local
" variables etc.
" This also sets up the rx for the different viki name types.
" VikiSetupBuffer(state, ?dontSetup='')
function! VikiSetupBuffer(state, ...) "{{{3
if !g:vikiEnabled
return
endif
" echom "DBG ". expand('%') .': '. (exists('b:vikiFamily') ? b:vikiFamily : 'default')
let dontSetup = a:0 > 0 ? a:1 : ""
let noMatch = ""
if exists("b:vikiNoSimpleNames") && b:vikiNoSimpleNames
let b:vikiNameTypes = substitute(b:vikiNameTypes, '\Cs', '', 'g')
endif
if exists("b:vikiDisableType") && b:vikiDisableType != ""
let b:vikiNameTypes = substitute(b:vikiNameTypes, '\C'. b:vikiDisableType, '', 'g')
endif
call VikiSetBufferVar("vikiAnchorMarker")
call VikiSetBufferVar("vikiSpecialProtocols")
call VikiSetBufferVar("vikiSpecialProtocolsExceptions")
call VikiSetBufferVar("vikiMarkInexistent")
call VikiSetBufferVar("vikiTextstylesVer")
" call VikiSetBufferVar("vikiTextstylesVer")
call VikiSetBufferVar("vikiLowerCharacters")
call VikiSetBufferVar("vikiUpperCharacters")
call VikiSetBufferVar("vikiFeedbackMin")
if a:state == 1
call VikiSetBufferVar("vikiCommentStart",
\ "b:commentStart", "b:ECcommentOpen", "b:EnhCommentifyCommentOpen",
\ "*matchstr(&commentstring, '^\\zs.*\\ze%s')")
call VikiSetBufferVar("vikiCommentEnd",
\ "b:commentEnd", "b:ECcommentClose", "b:EnhCommentifyCommentClose",
\ "*matchstr(&commentstring, '%s\\zs.*\\ze$')")
elseif !exists('b:vikiCommentStart')
" This actually is an error.
if &debug != ''
echom "Viki: FTPlugin wasn't loaded. Viki requires :filetype plugin on"
endif
let b:vikiCommentStart = '%'
let b:vikiCommentEnd = ''
endif
let b:vikiSimpleNameQuoteChars = '^][:*/&?<>|\"'
let b:vikiSimpleNameQuoteBeg = '\[-'
let b:vikiSimpleNameQuoteEnd = '-\]'
let b:vikiQuotedSelfRef = "^". b:vikiSimpleNameQuoteBeg . b:vikiSimpleNameQuoteEnd ."$"
let b:vikiQuotedRef = "^". b:vikiSimpleNameQuoteBeg .'.\+'. b:vikiSimpleNameQuoteEnd ."$"