-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathirfc.el
1542 lines (1423 loc) · 57.9 KB
/
irfc.el
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
;;; irfc.el --- Interface for IETF RFC document.
;; Filename: irfc.el
;; Description: Interface for IETF RFC document.
;; Author: Andy Stewart <lazycat.manatee@gmail.com>
;; Juanma Barranquero <lekktu@gmail.com>
;; Maintainer: Niels Widger <niels.widger@gmail.com>
;; Copyright (C) 2009, Andy Stewart, all rights reserved.
;; Copyright (C) 2009, Juanma Barranquero, all rights reserved.
;; Copyright (C) 2010, Niels Widger, all rights reserved.
;; Created: 2009-01-14 08:13:15
;; Version: 0.5.6
;; Last-Updated: Fri Aug 17 19:42:29 2012 (-0400)
;; By: Samuel Bronson
;; URL: http://www.emacswiki.org/emacs/download/irfc.el
;; Keywords: RFC, IETF
;; Compatibility: GNU Emacs 22 ~ 23
;;
;; Features that might be required by this library:
;;
;; `cl' `url-vars' `thingatpt'
;;
;;; This file is NOT part of GNU Emacs
;;; License
;;
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 3, or (at your option)
;; any later version.
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with this program; see the file COPYING. If not, write to
;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth
;; Floor, Boston, MA 02110-1301, USA.
;; Introduction:
;;
;; For historical reasons, IETF Internet RFCs are required to be in a plain
;; ASCII text format that's best-suited for sending directly to a 6-lpi
;; US-letter-size printer. This makes them suboptimal for viewing on-screen,
;; as you will be doing for countless hours if you're ever doing network
;; programming to one of them. Fortunately, the ASCII format is usually
;; close to what you, the Emacs zealot, *truly* want -- which is a format
;; suited to more pleasurably viewing the RFC in Emacs.
;;
;; The `irfc' package uses Emacs overlays to add some fortification and
;; hide the page headers and footers (which it replaces with one-line page
;; number references that look like "(p.1)", right-justified). The file is
;; never modified, and you can see the raw ASCII text by pressing `T'.
;;
;;; Commentary:
;;
;; Interface for IETF RFC document.
;;
;; This package use some code from `rfcview.el'.
;; Thanks "Neil W. Van Dyke"!
;;
;; The features this package provide:
;;
;; * Format RFC document for easy reading.
;; * Single keystroke for fast view.
;; * Render status switch.
;; * Smart table and content switch.
;; * Visit RFC link around point.
;; * Jump to RFC reference around point.
;; * Download RFC document *asynchronous*.
;;
;; Below are commands you can use:
;;
;; `irfc-render-toggle' Toggle render status with RFC buffer.
;; `irfc-quit' Quit RFC buffer.
;; `irfc-visit' Ask for RFC number and visit document.
;; `irfc-reference-goto' Ask for RFC reference and jump to it.
;; `irfc-head-goto' Ask for heading name and jump to it.
;; `irfc-head-number-goto' Ask for heading number and jump to it.
;; `irfc-follow' Visit RFC document around point.
;; `irfc-table-jump' Switch between table and content.
;; `irfc-page-goto' Goto page.
;; `irfc-page-next' Jump next page.
;; `irfc-page-prev' Jump previous page.
;; `irfc-page-first' Jump first page.
;; `irfc-page-last' Jump last page.
;; `irfc-page-table' Jump table page.
;; `irfc-head-next' Jump next heading.
;; `irfc-head-prev' Jump previous heading.
;; `irfc-rfc-link-next' Jump next RFC link.
;; `irfc-rfc-link-prev' Jump previous RFC link.
;; `irfc-scroll-up-one-line' Scroll up one line.
;; `irfc-scroll-down-one-line' Scroll down one line.
;;
;; Tips:
;;
;; You can use command `irfc-render-toggle' to toggle render status.
;;
;; Command `irfc-table-jump' can switch between table and content,
;; example you stay cursor at *table*, and type "G" will jump corresponding
;; content in buffer, alike, you can stay at any content and type "G"
;; will jump corresponding table item.
;;
;; Command `irfc-follow' will visit RFC document around point,
;; example you stay cursor at "[RFC3986]", and type "o" will
;; open rfc3986.txt in storage directory. If have not found
;; this file in directory, will download from `http://www.ietf.org/rfc/'
;; and open it when download complete.
;;
;; And command ‘irfc-follow’ can also use at title of RFC document.
;; Example rfc3986.txt contain “Obsoletes: 2732, 2396, 1808” at title,
;; you can move cursor to “2732” and type “o” will visit RFC 2732 document.
;; ‘irfc-follow’ support below keywords in title:
;;
;; “Request for Comments:”
;; “Updates:”
;; “Obsoletes:”
;;
;; You can use command `irfc-rfc-link-next' or `irfc-rfc-link-prev'
;; to jump next or previous RFC link in document.
;;
;; Command `irfc-visit' will ask the user for a RFC number and will
;; visit that document, either from `irfc-directory', if exists, or by
;; downloading it. This command can serve as entry point for Irfc,
;; to go to a RFC without having to visit the file or remember
;; whether it is already in `irfc-directory'.
;; And if you visit same document with your previous type, so just
;; hit RET, and don't need type RFC document number.
;;
;; Command `irfc-reference-goto' will ask the user for a reference
;; number and will jump to that citation in the Normative
;; References/Informative References heading.
;;
;; Command `irfc-head-goto' will ask the user for a heading name and
;; will jump to that heading. Completion list in minibuffer is
;; available.
;;
;; Command `irfc-head-number-goto' will ask the user for a heading
;; number and will jump to that heading. Completion list in minibuffer
;; is available.
;;
;;; Installation:
;;
;; Put irfc.el to your load-path.
;; The load-path is usually ~/elisp/.
;; It's set in your ~/.emacs like this:
;; (add-to-list 'load-path (expand-file-name "~/elisp"))
;;
;; And the following to your ~/.emacs startup file.
;;
;; (require 'irfc)
;;
;; Setup your storage directory for RFC documents.
;;
;; (setq irfc-directory "YourStorageDirectory")
;;
;; If you want make RFC document load `irfc-mode' automatically,
;; setup like below:
;;
;; (setq irfc-assoc-mode t)
;;
;;; Customize:
;;
;; `irfc-assoc-mode' whether assoc RFC document with `irfc-mode'.
;; `irfc-directory' the storage directory for RFC document.
;; `irfc-download-base-url' the base url for download RFC document.
;; `irfc-buffer-name-includes-title' whether buffer name should
;; include the RFC document's title
;; `irfc-highlight-requirement-keywords' whether RFC requirement
;; keywords specified in `irfc-requirement-keywords' list
;; should be highlighted using the face specified by
;; `irfc-requirement-keyword-face'.
;; `irfc-requirement-keywords' list of RFC requirement keywords to
;; highlight if `irfc-highlight-requirement-keywords' is t.
;; `irfc-highlight-references' whether RFC references should be
;; highlighted using the face specified by `irfc-reference-face'.
;;
;; All of the above can customize by:
;; M-x customize-group RET irfc RET
;;
;;; Change log:
;; 2012/08/17
;; * Samuel Bronson:
;; * Added `autoload' cookies in key locations.
;; * Modified `irfc-open' to create the `irfc-directory' if it's
;; missing (after verifying that the user is okay with this).
;; * Now, the user can install using e.g. `el-get' and never have
;; to touch init!
;;
;; 2011/07/12
;; * Juanma Barranquero:
;; * Fixed let-binding in `irfc-render-buffer'.
;; * Use `string-to-number' instead of `string-to-int'.
;; * Use `when' whenever appropriate.
;; * Lowercase arg of `irfc-current-head'.
;; * Remove unused local variable in `irfc-rfc-link-prev'.
;; * Add leading underscore to unused parameters in `irfc-fill-tables'
;; (that removes bytecompiler warnings if compiled under lexical
;; binding in Emacs 24+).
;; * Remove `function' from lambda expressions in
;; `irfc-overlay-put-alist' and `irfc-overlay-remove-all', and use
;; `mapc' instead of `mapcar'.
;; * Use `nconc' in `irfc-overlay-remove-all' to avoid a bit of
;; unnecessary consing when dealing with temporary lists.
;; * Remove unused local variable in `irfc-get-buffer' and simplify
;; format call (no need to pass as argument a constant string).
;; * Several fixes in docstrings and error messages.
;;
;; 2010/09/28
;; * Niels Widger:
;; * Added new mappings: "f" to `irfc-head-goto' and "F"
;; to `irfc-head-number-goto'.
;; * Added new variables: `irfc-heading-names-table',
;; `irfc-heading-names-list', `irfc-heading-numbers-table'
;; and `irfc-heading-numbers-list'.
;; * Added new functions: `irfc-read-heading-name',
;; `irfc-read-heading-number', `irfc-heading-number-at-point',
;; `irfc-head-goto', `irfc-head-number-goto' and
;; `irfc-fill-tables'.
;; * `irfc-render-buffer' makes new call to `irfc-fill-tables'.
;;
;; 2010/09/24
;; * Niels Widger:
;; * Added new function `irfc-reference-goto' that prompts a user
;; for a reference number and jumps to that citation.
;; * Added mapping from "r" to `irfc-reference-goto' in keymap.
;; * Added several helper functions used by `irfc-reference-goto':
;; `irfc-read-reference', `irfc-reference-at-point' and
;; `irfc-current-head'.
;; * Added requirement for `thingatpt'.
;;
;; 2010/09/23
;; * Niels Widger:
;; * Added new RFC requirement keyword overlay and RFC reference
;; overlay.
;; * Several new variables: `irfc-highlight-requirement-keywords',
;; `irfc-highlight-references' and `irfc-requirement-keywords'.
;; * New faces: `irfc-requirement-keyword-face' and
;; `irfc-reference-face'.
;; * New overlays: `irfc-requirement-keyword-overlay' and
;; `irfc-reference-overlay'.
;; * Modified `irfc-render-buffer' to call
;; `irfc-render-buffer-overlay-requirement-keyword' and
;; `irfc-render-buffer-overlay-reference'.
;;
;; 2010/09/20
;; * Niels Widger:
;; * New variable `irfc-buffer-name-includes-title'.
;; * Add new function `irfc-rename-buffer' to include RFC document
;; title in buffer name if `irfc-buffer-name-includes-title' is t.
;; * Modify `irfc-render-buffer' to call `irfc-rename-buffer'
;; function.
;;
;; 2009/02/13
;; * Andy Stewart:
;; * New variable `irfc-table-regex'.
;; * Fix bug of `irfc-table-jump'.
;; * Fix doc.
;;
;; 2009/01/29
;; * Andy Stewart:
;; * Fix overlay RFC link (as format [RFC-number]) in RFC1034.txt.
;; * Fix RFC link jump bug.
;;
;; 2009/01/22
;; * Juanma Barranquero
;; * Add require information to avoid compile warning.
;; * Add new function `irfc-unload-function' to cleanup
;; when execute command `unload-feature'.
;;
;; 2009/01/21
;; * Juanma Barranquero
;; * Add new command `irfc-visit' for fast open or download RFC
;; document.
;; * Fix doc.
;; * Andy Stewart:
;; * Applied Juanma's patch (with slightly modified). Thanks!
;; * Add variable `irfc-last-visit-number' to record last input
;; RFC document number, save type if have to visit same document
;; with previous times.
;; * Fix bug of function `irfc-download-callback'.
;; Display error information when download RFC document failed.
;;
;; 2009/01/18
;; * Andy Stewart:
;; * Make `irfc-follow' can open RFC link at title.
;; Now support below keyword in title:
;; "Request for Comments:"
;; "Updates:"
;; "Obsoletes:"
;; * Add new commands: `irfc-rfc-link-next' and `irfc-rfc-link-prev'.
;; * Fix doc.
;;
;; * Juanma Barranquero:
;; * Fix defface error, and improve document.
;;
;; 2009/01/17
;; * Andy Stewart:
;; * Fix doc.
;; * Remove function `irfc-render-buffer-hide-cr'.
;; * Thanks "Juanma Barranquero" improve document and advices. :)
;;
;; 2009/01/16
;; * Andy Stewart:
;; * Modified code for 22 compatibility.
;; * Fix doc.
;;
;; 2009/01/14
;; * Andy Stewart:
;; * First released.
;;
;;; Acknowledgements:
;;
;; Neil W. Van Dyke <neil@neilvandyke.org>
;; For create rfcview.el
;; Juanma Barranquero <lekktu@gmail.com>
;; Thanks Juanma Barranquero send many patches.
;; Juanma, thank you very much! :)
;;
;;; TODO
;;
;;
;;
;;; Require
(eval-when-compile (require 'cl))
(require 'url-vars)
(require 'thingatpt)
;;; Code:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Customize ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;###autoload
(defgroup irfc nil
"Interface for IETF RFC documents."
:group 'edit)
;; This is autoloaded so that it will take effect without users having
;; to `load'/`require' this package in their init file.
;;;###autoload
(defcustom irfc-assoc-mode nil
"If non-nil, RFC documents are associated with `irfc-mode'.
Default is nil."
:type 'boolean
:set (lambda (symbol value)
(set symbol value)
(if value
(add-to-list 'auto-mode-alist
'("/rfc[0-9]+\\.txt\\'" . irfc-mode))
(remove-hook 'auto-mode-alist
'("/rfc[0-9]+\\.txt\\'" . irfc-mode))))
:group 'irfc)
(defcustom irfc-directory "~/.emacs.d/RFC/"
"The storage directory for RFC document download and search."
:type 'string
:group 'irfc)
(defcustom irfc-download-base-url "http://www.ietf.org/rfc/"
"The base URL for downloading RFC documents."
:type 'string
:group 'irfc)
(defcustom irfc-buffer-name-includes-title t
"If non-nil, buffer names for RFC documents will include the RFC title.
The format for the buffer name will be 'RFCTITLE (RFCNUM.TXT)'.
If nil, the buffer name is just RFCNUM.TXT. Default is t."
:type 'boolean
:group 'irfc)
(defcustom irfc-highlight-requirement-keywords t
"If non-nil, requirement keywords specified by
`irfc-requirement-keywords' list will be highlighted using the
face specified by `irfc-requirement-keyword-face'.
Default is t."
:type 'boolean
:group 'irfc)
(defcustom irfc-highlight-references t
"If non-nil, RFC document references specified by the
`irfc-reference-regex' regular expression will be highlighted
using the face specified by `irfc-reference-face'. Default is
t."
:type 'boolean
:group 'irfc)
(defcustom irfc-requirement-keywords '("MUST" "MUST NOT"
"REQUIRED"
"SHALL" "SHALL NOT"
"SHOULD" "SHOULD NOT"
"RECOMMENDED" "NOT RECOMMENDED"
"MAY" "OPTIONAL" "NOT")
"List of requirement keyword strings to be highlighted if
`irfc-highlight-requirement-keywords' is t."
:type '(repeat (string))
:group 'irfc)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Faces ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defface irfc-title-face
'((t (:foreground "Gold" :bold t)))
"Face used for titles."
:group 'irfc)
(defvar irfc-title-overlay nil
"Overlay for `irfc-title-face'.")
(defface irfc-head-name-face
'((t (:foreground "DarkRed" :bold t :underline t)))
"Face used for heading names."
:group 'irfc)
(defvar irfc-head-name-overlay nil
"Overlay for `irfc-head-name-face'.")
(defface irfc-head-number-face
'((t (:foreground "DarkRed" :bold t)))
"Face used for heading numbers."
:group 'irfc)
(defvar irfc-head-number-overlay nil
"Overlay for `irfc-head-number-face'.")
(defface irfc-rfc-number-face
'((t (:foreground "Green3" :bold t)))
"Face used for RFC number in the header."
:group 'irfc)
(defvar irfc-rfc-number-overlay nil
"Overlay for `irfc-rfc-number-face'.")
(defface irfc-std-number-face
'((t (:foreground "Grey" :bold t)))
"Face used for STD number in the header."
:group 'irfc)
(defvar irfc-std-number-overlay nil
"Overlay for `irfc-std-number-face'.")
(defface irfc-rfc-link-face
'((t (:foreground "Grey30" :bold t)))
"Face used for RFC link in the header."
:group 'irfc)
(defvar irfc-rfc-link-overlay nil
"Overlay for `irfc-rfc-link-face'.")
(defface irfc-table-item-face
'((t (:foreground "LawnGreen")))
"Face used for Table item."
:group 'irfc)
(defvar irfc-table-item-overlay nil
"Overlay for `irfc-table-item-face'.")
(defface irfc-requirement-keyword-face
'((t (:foreground "red1" :bold t)))
"Face used for requirement keywords."
:group 'irfc)
(defvar irfc-requirement-keyword-overlay nil
"Overlay for `irfc-requirement-keyword-face'.")
(defface irfc-reference-face
'((t (:foreground "blue1" :bold t)))
"Face used for RFC document references."
:group 'irfc)
(defvar irfc-reference-overlay nil
"Overlay for `irfc-reference-face'.")
(defvar irfc-hide-overlay nil
"Overlay for hiding whitespace or blank lines.")
(defvar irfc-page-number-overlay nil
"Overlay for page number.")
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Variables ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defvar irfc-mode-map
(let ((map (make-sparse-keymap)))
(define-key map (kbd "j") 'next-line)
(define-key map (kbd "k") 'previous-line)
(define-key map (kbd "h") 'backward-char)
(define-key map (kbd "l") 'forward-char)
(define-key map (kbd "e") 'scroll-down)
(define-key map (kbd "SPC") 'scroll-up)
(define-key map (kbd "J") 'irfc-scroll-up-one-line)
(define-key map (kbd "K") 'irfc-scroll-down-one-line)
(define-key map (kbd ",") 'end-of-buffer)
(define-key map (kbd ".") 'beginning-of-buffer)
(define-key map (kbd "T") 'irfc-render-toggle)
(define-key map (kbd "q") 'irfc-quit)
(define-key map (kbd "o") 'irfc-follow)
(define-key map (kbd "v") 'irfc-visit)
(define-key map (kbd "r") 'irfc-reference-goto)
(define-key map (kbd "f") 'irfc-head-goto)
(define-key map (kbd "F") 'irfc-head-number-goto)
(define-key map (kbd "g") 'irfc-page-goto)
(define-key map (kbd "N") 'irfc-page-next)
(define-key map (kbd "P") 'irfc-page-prev)
(define-key map (kbd ">") 'irfc-page-last)
(define-key map (kbd "<") 'irfc-page-first)
(define-key map (kbd "b") 'irfc-page-table)
(define-key map (kbd "H") 'irfc-head-next)
(define-key map (kbd "L") 'irfc-head-prev)
(define-key map (kbd "G") 'irfc-table-jump)
(define-key map (kbd "<tab>") 'irfc-rfc-link-next)
(define-key map (kbd "<backtab>") 'irfc-rfc-link-prev)
map)
"Keymap used by `irfc-mode'.")
(defvar irfc-stock-section-names
'("abstract"
"acknowledgement"
"acknowledgements"
"acknowledgment"
"acknowledgments"
"appendices"
"author's address"
"authors' addresses"
"bibliography"
"chair's address"
"copyright notice"
"copyright statement"
"editor's address"
"editors' addresses"
"full copyright notice"
"full copyright statement"
"iesg note"
"index"
"introduction"
"references and bibliography"
"references"
"security considerations"
"status of this memo"
"table of contents")
"The stock name for overlay heading.")
(defvar irfc-download-buffer nil
"Download buffer used by `url-retrieve'.
This variable is always buffer-local.")
(make-variable-buffer-local 'irfc-download-buffer)
(defvar irfc-download-url nil
"URL from which to download files.
This variable is always buffer-local.")
(make-variable-buffer-local 'irfc-download-url)
(defvar irfc-render-p t
"Render status for RFC buffer.
This variable is always buffer-local.")
(make-variable-buffer-local 'irfc-render-p)
(defvar irfc-total-pages 0
"Total number of pages in RFC buffer.
This variable is always buffer-local.")
(make-variable-buffer-local 'irfc-total-pages)
(defvar irfc-heading-names-list nil
"List of heading names in RFC buffer.
This variable is buffer-local in buffers where `irfc-mode' has
been called.")
(defvar irfc-heading-numbers-list nil
"List of heading numbers in RFC buffer.
This variable is buffer-local in buffers where `irfc-mode' has
been called.")
(defvar irfc-heading-names-table nil
"Table mapping heading names to position in RFC buffer.
This variable is buffer-local in buffers where `irfc-mode' has
been called.")
(defvar irfc-heading-numbers-table nil
"Table mapping heading numbers to position in RFC buffer.
This variable is buffer-local in buffers where `irfc-mode' has
been called.")
(defvar irfc-last-visit-number nil
"Number of the last RFC document visited.")
(defvar irfc-table-regex "^[ ]+\\([A-Z]?[0-9\\.]*\\)[ ]+\\([^\\.\n]+\\)[\\. ]+\\([0-9]+\\)$"
"The regular-expression that match table item.")
(defvar irfc-reference-regex "\\[[0-9]+]"
"The regular-expression that matches normative/informative
references.")
(defvar irfc-reference-format-regex "\\[%d]"
"The format string for use with `format' function for creating
regular-expressions that match a normative/informative
reference.")
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Interactive functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;###autoload
(define-derived-mode irfc-mode text-mode "Irfc"
"Major mode for IETF RFC documents."
;; Setup.
(use-local-map irfc-mode-map)
(setq buffer-read-only t)
(setq font-lock-defaults nil)
(auto-save-mode 0)
(make-local-variable 'irfc-heading-names-list)
(make-local-variable 'irfc-heading-numbers-list)
(make-local-variable 'irfc-heading-names-table)
(make-local-variable 'irfc-heading-numbers-table)
(setq irfc-heading-names-table (make-hash-table :test 'equal))
(setq irfc-heading-numbers-table (make-hash-table :test 'equal))
(setq irfc-heading-names-list nil)
(setq irfc-heading-numbers-list nil)
;; Render.
(irfc-render-buffer))
(defun irfc-render-buffer ()
"Render RFC buffer."
(interactive)
(save-excursion
(let ((case-fold-search nil)
(top-point (point-min))
(title-line-point nil)
temp-point)
;; Clean up overlays.
(irfc-overlay-remove-all)
;; Hide whitespace at start of file.
(setq temp-point (irfc-render-buffer-hide-whitespace-at-start))
(when temp-point (setq top-point temp-point))
;; Hide any extraneous blank lines.
(setq title-line-point (irfc-render-buffer-hide-blank-line top-point))
;; Add overlays for page headers and footers.
(irfc-render-buffer-overlay-page-number)
;; Add overlay for the RFC number.
(irfc-render-buffer-overlay-rfc-number top-point title-line-point)
;; Add overlay for the STD number.
(irfc-render-buffer-overlay-std-number top-point title-line-point)
;; Add overlay for the table item.
(irfc-render-buffer-overlay-table-item top-point)
;; Add overlay for the RFC link.
(irfc-render-buffer-overlay-rfc-link top-point)
;; Add overlay for the title.
(irfc-render-buffer-overlay-title title-line-point)
;; Add overlay for the heading.
(irfc-render-buffer-overlay-head title-line-point)
;; Add overlay for requirement keywords.
(when irfc-highlight-requirement-keywords
(irfc-render-buffer-overlay-requirement-keyword top-point))
;; Add overlay for references.
(when irfc-highlight-references
(irfc-render-buffer-overlay-reference top-point))
;; Rename buffer
(irfc-rename-buffer title-line-point)
;; Fill heading names/numbers tables
(irfc-fill-tables title-line-point))))
(defun irfc-render-toggle ()
"Toggle RFC buffer render status."
(interactive)
(if irfc-render-p
(irfc-render-turn-off)
(irfc-render-turn-on)))
(defun irfc-render-turn-on ()
"Turn on RFC buffer render status."
(irfc-render-buffer)
(setq irfc-render-p t))
(defun irfc-render-turn-off ()
"Turn off RFC buffer render status."
(irfc-overlay-remove-all)
(setq irfc-render-p nil))
(defun irfc-quit ()
"Quit RFC buffer."
(interactive)
(kill-buffer (current-buffer)))
(defun irfc-table-jump ()
"Jump between table and content.
You can jump to the corresponding table item when you are at content.
You can jump to the corresponding content when you are at table."
(interactive)
(if (irfc-have-table-p)
(let ((original-position (point))
head-name
page-number
match-list)
(cond ((irfc-in-table-p)
;; When in table.
(beginning-of-line)
(if (search-forward-regexp irfc-table-regex (line-end-position) t)
;; Jump content when find valid table item.
(progn
;; Get head name and page number.
(setq head-name (match-string 0))
(setq head-name (replace-regexp-in-string "[\\. ]+\\([0-9]+\\)$" "" head-name))
(setq head-name (replace-regexp-in-string "^[ ]+" "" head-name))
(setq page-number (string-to-number (match-string 3)))
;; Jump page.
(irfc-page-goto page-number)
;; Search head.
(re-search-forward head-name nil t)
;; Indent.
(back-to-indentation))
;; Restore original position and output message
;; when at invalid table item.
(message "Invalid table item.")
(goto-char original-position)))
;; Do nothing when at front of table.
((irfc-front-table-p)
(message "In front of table."))
;; Jump corresponding table item from content.
(t
;; Get head name and page number.
(end-of-line)
(setq match-list (irfc-head-move t))
(setq head-name (buffer-substring-no-properties (nth 2 match-list)
(nth 3 match-list)))
(setq page-number (irfc-current-page))
;; Jump table.
(irfc-page-table)
;; Search head.
(re-search-forward (concat (regexp-quote head-name) "[\\. ]+"
(regexp-quote (number-to-string page-number))))
;; Indent.
(back-to-indentation))))
;; Do nothing when haven't table in this RFC document.
(message "This RFC document contains no Table of Contents.")))
(defun irfc-reference-goto (&optional number)
"Goto reference NUMBER."
(interactive (list (irfc-read-reference)))
(let ((original-position (point)) (done nil) (found nil) (beg) (end))
(goto-char (point-min))
(while (not done)
(if (not (re-search-forward
(concat "^[ \t]*"
(format irfc-reference-format-regex number))
(point-max) t))
(setq done t)
(setq beg (match-beginning 0))
(setq end (match-end 0))
(let ((name (irfc-current-head)))
(if (not (or (string= name "References")
(string= name "Normative References")
(string= name "Informative References")))
(goto-char end)
(goto-char beg)
(setq found t)
(setq done t)))))
(when (not found)
(goto-char original-position)
(message "Cannot find reference %d" number))))
(defun irfc-read-reference ()
"Read reference as a number using a reference found at point as
default."
(let ((default (irfc-reference-at-point)))
(if (eq default nil)
(read-number "Reference number: ")
(read-number "Reference number: " default))))
(defun irfc-reference-at-point ()
"Returns reference at point as a number or nil if one is not
found."
(if (not (thing-at-point-looking-at irfc-reference-regex))
nil
(let* ((match (buffer-substring (match-beginning 0) (match-end 0)))
(len (length match)))
(string-to-number (substring match 1 (1- len))))))
(defun irfc-read-heading-name ()
"Read heading name as a string."
(completing-read "Heading name: " irfc-heading-names-list nil t))
(defun irfc-read-heading-number ()
"Read heading number as a string using a heading number found
at point as default."
(let ((default (irfc-heading-number-at-point)))
(completing-read
(concat "Heading number" (if (eq default nil) "" (format " (default %s)" default)) ": ")
irfc-heading-numbers-list nil t nil nil default nil)))
(defun irfc-heading-number-at-point ()
"Returns heading number at point as a string or nil if one is
not found."
(if (not (thing-at-point-looking-at "\\([0-9]+\\.\\)*[0-9]+"))
nil
(let ((match (match-string 0)))
(cond ((member match irfc-heading-numbers-list) match)
((member (concat match ".") irfc-heading-numbers-list) (concat match "."))))))
(defun irfc-page-goto (number)
"Goto page NUMBER."
(interactive "nPage number: ")
(cond ((<= number 1)
;; Move beginning of buffer when page number
;; is equal or below 1.
(call-interactively 'beginning-of-buffer)
(when (< number 1)
(message "Top page reached.")))
(t
;; Move special page.
(let ((original-position (point))
(original-render-status irfc-render-p)
reach-bottom-p)
;; Set max page number when
;; query page is above max limit.
(when (> number irfc-total-pages)
(setq number irfc-total-pages)
(setq reach-bottom-p t))
;; Turn off render.
(irfc-render-turn-off)
;; Search page number.
(goto-char (point-min))
(if (re-search-forward (concat "\\[Page "
(regexp-quote (number-to-string (1- number)))
"\\]$")
nil t)
;; Move special page when search successful.
(progn
;; Adjust cursor position.
(forward-line +3)
(re-search-forward "^.+$" nil t)
(back-to-indentation)
;; Recenter when reach bottom page.
(when reach-bottom-p
(recenter 0)
(message "Bottom page reached.")))
;; Restore original position when search failed.
(goto-char original-position))
;; Revert render status.
(unless (equal original-render-status irfc-render-p)
(irfc-render-toggle))))))
(defun irfc-page-next (arg)
"Move to next ARGth page.
ARG defaults to 1."
(interactive "P")
(irfc-page-goto (+ (irfc-current-page) (or arg 1))))
(defun irfc-page-prev (arg)
"Move to previous ARGth page.
ARG defaults to 1."
(interactive "P")
(irfc-page-goto (- (irfc-current-page) (or arg 1))))
(defun irfc-page-first ()
"Move to first page."
(interactive)
(irfc-page-goto 1))
(defun irfc-page-last ()
"Move to last page."
(interactive)
(irfc-page-goto irfc-total-pages))
(defun irfc-page-table ()
"Move to Table of Contents."
(interactive)
(if (irfc-have-table-p)
(progn
(goto-char (point-min))
(re-search-forward "^Table of Contents$" nil t)
(back-to-indentation))
(message "This RFC document has no Table of Contents.")))
;;;###autoload
(defun irfc-follow ()
"Open RFC document around point.
Download and open RFC document if it
does not exist in `irfc-directory'."
(interactive)
(let ((rfc-file-name (irfc-get-rfc-filename)))
(if rfc-file-name
;; Open RFC document.
(irfc-open rfc-file-name)
(message "No valid RFC link found at cursor."))))
;;;###autoload
(defun irfc-visit (&optional rfc-number)
"Open RFC document RFC-NUMBER.
Download and open RFC document if it
does not exist in `irfc-directory'."
(interactive)
(or rfc-number
(setq rfc-number (read-number
"RFC document to visit: "
irfc-last-visit-number)))
(setq irfc-last-visit-number rfc-number)
(irfc-open (format "rfc%s.txt" rfc-number)))
(defun irfc-head-goto (NAME)
"Goto heading NAME."
(interactive (list (irfc-read-heading-name)))
(let ((new-point (gethash NAME irfc-heading-names-table)))
(if (eq new-point nil)
(message "Cannot find heading \"%s\"" NAME)
(goto-char new-point)
(back-to-indentation))))
(defun irfc-head-next ()
"Move to next heading."
(interactive)
(let ((original-position (point)))
(end-of-line)
(if (irfc-head-move)
;; Move to next heading,
;; when search successful.
(beginning-of-line)
;; Restore original position
;; when search failed.
(goto-char original-position)
(message "No next heading."))))
(defun irfc-head-prev ()
"Move to previous heading."
(interactive)
(let ((original-position (point)))
(beginning-of-line)
(unless (irfc-head-move t)
;; Restore original position
;; when search failed.
(goto-char original-position)
(message "No previous heading."))))
(defun irfc-current-head (&optional print)
"Returns name of the current heading.
If optional argument PRINT is non-nil, print the name before returning it."
(interactive)
(save-excursion
(irfc-head-prev)
(re-search-forward "^\\([0-9]+\\.\?\\)+[ \t]+" (line-end-position) t)
(let ((name (buffer-substring (point) (line-end-position))))
(when print
(message "%s" name))
name)))
(defun irfc-head-number-goto (NAME)
"Goto heading number NAME."
(interactive (list (irfc-read-heading-number)))
(let ((new-point (gethash NAME irfc-heading-numbers-table)))
(if (eq new-point nil)
(irfc-head-number-goto (concat NAME "."))
(goto-char new-point)
(back-to-indentation))))
(defun irfc-scroll-up-one-line ()
"Scroll up one line."
(interactive)
(scroll-up 1))
(defun irfc-scroll-down-one-line ()
"Scroll down one line."
(interactive)
(scroll-down 1))
(defun irfc-rfc-link-next ()
"Move the point to the next RFC link."
(interactive)
(let ((original-point (point)))
(when (re-search-forward "\\(\\B\\[RFC-?[0-9]+\\]\\B\\|[ \t]+[0-9]+\\)" nil t)
(catch 'match
(while (and (not (string-match "\\[\\(RFC-?[0-9]+\\)\\]" (irfc-get-symbol-non-blank)))
(or (not (irfc-title-rfc-link-p)) ;not valid RFC link number
(eolp))) ;number at end of line is invalid RFC number
(unless (re-search-forward "\\(\\B\\[RFC-?[0-9]+\\]\\B\\|[ \t]+[0-9]+\\)" nil t)
(goto-char original-point)
(message "No next RFC link.")
(throw 'match "Match last one.")))))))
(defun irfc-rfc-link-prev ()
"Move the point to the previous RFC link."
(interactive)
(when (re-search-backward "\\(\\B\\[RFC-?[0-9]+\\]\\B\\|[ \t]+[0-9]+\\)" nil t)
(catch 'match
(while
;; Not match [RFCnnn] format.
(not (string-match "\\[\\(RFC-?[0-9]+\\)\\]" (irfc-get-symbol-non-blank)))
(skip-chars-forward " ")
(if (and (irfc-title-rfc-link-p) ;is valid RFC link number
(save-excursion ;skip number at end of line.
(search-forward-regexp "[0-9]+" nil t)
(not (eolp))))
(progn
(when (string-match "^request for comments:[ \t]+$"
(buffer-substring-no-properties (line-beginning-position)
(point)))
(message "No previous RFC link."))
(throw 'match "Match title RFC link."))
(re-search-backward "\\(\\B\\[RFC-?[0-9]+\\]\\B\\|[ \t]+[0-9]+\\)" nil t))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Utilities functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun irfc-open (rfc-file-name)
"Open RFC document with RFC-FILE-NAME."
;; Make sure `irfc-directory' exists.
(unless (file-directory-p irfc-directory)
(if (y-or-n-p (format "Create directory %s to hold RFCs? "
irfc-directory))
(make-directory irfc-directory t)
(error "Customize `irfc-directory', then!")))