1. xemacs
  2. hyperbole

Source

hyperbole / kotl / kimport.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
;;!emacs
;;
;; FILE:         kimport.el
;; SUMMARY:      Convert and insert other outline file formats into koutlines.
;; USAGE:        GNU Emacs V19 Lisp Library
;; KEYWORDS:     data, outlines, wp
;;
;; AUTHOR:       Bob Weiner
;; ORG:          BeOpen.com
;;
;; ORIG-DATE:    15-Nov-93 at 11:57:05
;; LAST-MOD:     12-Jul-99 at 23:00:10 by Bob Weiner
;;
;; Copyright (C) 1993-1999  BeOpen.com
;; See the "../HY-COPY" file for license information.
;;
;; This file is part of Hyperbole.

;;; ************************************************************************
;;; Other required Elisp libraries
;;; ************************************************************************

;; kfile.el requires kotl-mode.el which requires kimport.el.
(require 'wrolo)

;;; ************************************************************************
;;; Public variables
;;; ************************************************************************

;;  kimport:mode-alist and kimport:suffix-alist are defined in
;;  "../hyperbole.el".

;;; ************************************************************************
;;; Public functions
;;; ************************************************************************

;;;###autoload
(defun kimport:file (import-from output-to &optional children-p)
  "Import a buffer or file IMPORT-FROM into the koutline in buffer or file OUTPUT-TO.

Any suffix in IMPORT-FROM's buffer name is used to determine the type of
importation.  All others are imported as text, one paragraph per cell.

See the documentation for the variable, `kimport:suffix-alist' for
information on specific importation formats."
  (interactive "FImport from buffer/file: \nFInsert into koutline buffer/file: \nP")
  (let ((import-buf-name
	 (cond ((or (bufferp import-from)
		    (get-buffer import-from))
		(buffer-name (get-buffer import-from)))
	       ((get-file-buffer import-from)
		(buffer-name (get-file-buffer import-from)))
	       ((stringp import-from)
		(file-name-nondirectory import-from))
	       (t (error "(kimport:buffer): `%s' is an invalid `import-from' argument"))))
	(function))

    (set-buffer import-buf-name)
    (if (setq function (cdr (assq major-mode kimport:mode-alist)))
	nil
      (let ((import-suffix (if (string-match "\\..+\\'" import-buf-name)
			       (match-string 0 import-buf-name)))
	    (suffix-alist kimport:suffix-alist)
	    suffix-regexp)
	(while (and import-suffix suffix-alist)
	  (setq suffix-regexp (car (car suffix-alist))
		function (cdr (car suffix-alist))
		suffix-alist (cdr suffix-alist))
	  (if (string-match suffix-regexp import-suffix)
	      nil
	    (setq function nil)))
	(if function nil (setq function (cdr (assq t kimport:mode-alist))))))
    (funcall function import-from output-to children-p)))

;;; Augment right-side numbered files, blank line between cells
;;;

;;;###autoload
(defun kimport:aug-post-outline (import-from output-to &optional children-p)
  "Insert Augment outline statements from IMPORT-FROM into koutline OUTPUT-TO.
Displays and leaves point in OUTPUT-TO.  See documentation for
`kimport:initialize' for valid values of IMPORT-FROM and OUTPUT-TO and for
an explanation of where imported cells are placed.

If OUTPUT-TO is a new koutline, the first statement inserted will be the
first cell.  Otherwise, it will be the successor of the current cell.

Each statement to be imported is delimited by an Augment relative id at the
end of the statement.  \"1\" = level 1, \"1a\" = level 2 in outline and so
on."
  (interactive "FImport from Augment post-numbered buffer/file: \nFBuffer/file to insert cells into: \nP")
  (let ((output-level 1) (klabel "1")
	initially-empty-output no-renumber orig-point count total)
    ;; Don't change the order of import-from and output-to inits here.
    (setq import-from (kimport:copy-and-set-buffer import-from)
	  output-to (kimport:initialize output-to)
	  orig-point (point)
	  initially-empty-output (zerop (- (point-max) (point-min)))
	  no-renumber (or initially-empty-output
			  (not (if children-p
				   (kcell-view:child-p)
				 (kcell-view:sibling-p)))))

    (if (eq import-from output-to)
	(error "(kimport:aug-post-outline): Import and output buffers may not be the same."))

    (set-buffer import-from)
    (show-all)
    (save-excursion
      (goto-char (point-min))
      ;; Total number of Augment statements.
      (setq total (read (count-matches
			 " +\\([0-9][0-9a-z]*\\)\n\\(\n\\|\\'\\)")))
      (if initially-empty-output
	  nil
	;; Insert first cell as sibling of current cell.
	(set-buffer output-to)
	(if children-p
	    ;; Insert as children.
	    (progn (setq klabel (klabel:child (kcell-view:label))
			 output-level (klabel:level klabel))
		   ;; Move to end of this cell since cell insertion will
		   ;; occur at point.
		   (goto-char (kcell-view:end)))
	;; Insert as successors.
	(setq klabel (klabel:increment (kcell-view:label))
	      output-level (klabel:level klabel))
	;; Move to start of line of next tree since cell insertion will occur
	;; at point.
	(goto-char (kotl-mode:tree-end))))
      (setq count (kimport:aug-post-statements
		   import-from output-to klabel output-level 1 0 total)))
    (pop-to-buffer output-to)
    (kfile:narrow-to-kcells)
    (if no-renumber nil (klabel-type:update-labels klabel))
    (goto-char orig-point)
    (if (kotl-mode:buffer-empty-p)
	nil
      (kotl-mode:to-valid-position))
    (message "Imported %d of %d Augment statements." count total)))

;;;
;;; Emacs outliner style files, leading `*' cell delimiters
;;;

;;;###autoload
(defun kimport:star-outline (import-from output-to &optional children-p)
  "Insert star outline nodes from IMPORT-FROM into koutline OUTPUT-TO.
Displays and leaves point in OUTPUT-TO.  See documentation for
`kimport:initialize' for valid values of IMPORT-FROM and OUTPUT-TO and for
an explanation of where imported cells are placed.

\"* \" = level 1, \"** \" = level 2 in outline and so on."
  (interactive "FImport from star delimited cells buffer/file: \nFBuffer/file to insert cells into: \nP")
  (let ((output-level 1) (klabel "1")
	initially-empty-output no-renumber orig-point count total) 
    ;; Don't change the order of import-from and output-to inits here.
    (setq import-from (kimport:copy-and-set-buffer import-from)
	  output-to (kimport:initialize output-to)
	  orig-point (point)
	  initially-empty-output (zerop (- (point-max) (point-min)))
	  no-renumber (or initially-empty-output
			  (not (if children-p
				   (kcell-view:child-p)
				 (kcell-view:sibling-p)))))

    (if (eq import-from output-to)
	(error "(kimport:star-outline): Import and output buffers may not be the same."))

    (set-buffer import-from)
    (show-all)
    (save-excursion
      (goto-char (point-min))
      ;; If initial text in buffer is not an star outline node, add a star to
      ;; make it one, so it is not deleted from the import.
      (if (not (looking-at "[ \t]*\\*"))
	  (insert "* "))
      (goto-char (point-min))
      ;; Total number of top-level cells.
      (setq total (read (count-matches "^[ \t]*\\*[ \t\n\r]")))
      (if initially-empty-output
	  nil
	;; Insert first cell as sibling of current cell.
	(set-buffer output-to)
	(if children-p
	    ;; Insert as children.
	    (progn (setq klabel (klabel:child (kcell-view:label))
			 output-level (klabel:level klabel))
		   ;; Move to end of this cell since cell insertion will
		   ;; occur at point.
		   (goto-char (kcell-view:end)))
	;; Insert as successors.
	(setq klabel (klabel:increment (kcell-view:label))
	      output-level (klabel:level klabel))
	;; Move to start of line of next tree since cell insertion will occur
	;; at point.
	(goto-char (kotl-mode:tree-end))))
      (setq count (kimport:star-entries
		   import-from output-to klabel output-level 1 0 total)))
    (pop-to-buffer output-to)
    (kfile:narrow-to-kcells)
    (if no-renumber nil (klabel-type:update-labels klabel))
    (goto-char orig-point)
    (if (kotl-mode:buffer-empty-p)
	nil
      (kotl-mode:to-valid-position))
    (message "Imported %d of %d star outline trees." count total)))

;;;
;;; Generic text file import or koutline insertion.
;;;

;;;###autoload
(defun kimport:text (import-from output-to &optional children-p)
  "Insert text paragraphs from IMPORT-FROM into koutline OUTPUT-TO.
Displays and leaves point in OUTPUT-TO.  See documentation for
`kimport:initialize' for valid values of IMPORT-FROM and OUTPUT-TO and for
an explanation of where imported cells are placed.

Text paragraphs are imported as a sequence of same level cells.  Koutlines
are imported with their structure intact.

The variable, `paragraph-start,' is used to determine paragraphs."
  (interactive "FImport from text/koutline buffer/file: \nFInsert cells into koutline buffer/file: \nP")
  (let ((klabel "1") (output-level 1) (count 0) initially-empty-output
	no-renumber orig-point total)
    ;; Don't change the order of import-from and output-to inits here.
    (setq import-from (kimport:copy-and-set-buffer import-from)
	  output-to (kimport:initialize output-to)
	  orig-point (point)
	  initially-empty-output (zerop (- (point-max) (point-min)))
	  no-renumber (or initially-empty-output
			  (not (if children-p
				   (kcell-view:child-p)
				 (kcell-view:sibling-p)))))

    (if (eq import-from output-to)
	(error "(kimport:text): Import and output buffers may not be the same."))

    (set-buffer import-from)
    (let ((kotl-import (eq major-mode 'kotl-mode))
	  visible-cells)
      (save-excursion
	(if initially-empty-output
	    nil
	  ;; Insert first cell as sibling of current cell.
	  (set-buffer output-to)
	  (if children-p
	      ;; Insert as children.
	      (progn (setq klabel (klabel:child (kcell-view:label))
			   output-level (klabel:level klabel))
		     ;; Move to end of this cell since cell insertion will
		     ;; occur at point.
		     (goto-char (kcell-view:end)))
	    ;; Insert as successors.
	    (setq klabel (klabel:increment (kcell-view:label))
		  output-level (klabel:level klabel))
	    ;; Move to start of line of next tree since cell insertion will occur
	    ;; at point.
	    (goto-char (kotl-mode:tree-end)))
	  (set-buffer import-from))

	(if kotl-import
	    ;; Importing from a koutline, so handle specially.
	    (progn (kotl-mode:beginning-of-buffer)
		   ;; Total number of cells.
		   (setq total (read (count-matches "[\n\r][\n\r]"))
			 visible-cells (read (count-matches "\n\n"))
			 count (save-excursion
				 ;; Incredible non-local exit to ensure that
				 ;; recursion ends at the right time.
				 (catch 'end
				   (kimport:kcells import-from output-to klabel
						   output-level 1
						   count total)))))

	  (show-all)
	  (goto-char (point-min))
	  ;; Total number of paragraphs.
	  (setq total (kimport:count-paragraphs)
		count (kimport:text-paragraphs import-from output-to klabel
					       output-level count total))))
      (pop-to-buffer output-to)
      (kfile:narrow-to-kcells)
      (if no-renumber nil (klabel-type:update-labels klabel))
      (goto-char orig-point)
      (if (kotl-mode:buffer-empty-p)
	  nil
	(kotl-mode:to-valid-position))
      (if kotl-import
	  (message "Imported %d of %d visible cells from a %d cell outline."
		   count visible-cells total)
	(message "Imported %d of %d paragraphs." count total)))))

;;; ************************************************************************
;;; Private functions
;;; ************************************************************************

(defun kimport:count-paragraphs ()
  "Return the number of paragraphs in the buffer based on `paragraph-separate'."
  (interactive)
  (let ((count 0) (in-between))
    (save-excursion
      (goto-char (point-min))
      (if (or (looking-at paragraph-separate)
	      (looking-at "[ \t]*\\S-"))
	  ;; Don't count this first paragraph since there typically will be
	  ;; an extra match at the end of the buffer due to blank lines.
	  (setq in-between t))
      (while (zerop (forward-line 1))
	(if (looking-at paragraph-separate)
	    (if (not in-between)
		(setq count (1+ count)
		      in-between t))
	  (setq in-between nil)))
      count)))

;;; ************************************************************************
;;; Special Private functions - Don't call these functions from outside of
;;; this module or you may misuse them and cause data corruption.
;;; ************************************************************************

(defun kimport:aug-label-lessp (label1 label2)
  "Return non-nil iff Augment-style LABEL1 is less than LABEL2."
  (let ((lev1 (klabel:level-alpha label1))
	(lev2 (klabel:level-alpha label2)))
    (cond ((< lev1 lev2))
	  ((= lev1 lev2) (string-lessp label1 label2))
	  (t nil))))

(defun kimport:aug-post-statements (import-from output-to klabel output-level
 			            import-level count total)
  "Insert post-numbered Augment statements (contents only) from IMPORT-FROM into existing OUTPUT-TO. 

KLABEL is the label to use for the first imported statement.
OUTPUT-LEVEL is the level at which to insert the first statement.
IMPORT-LEVEL is the depth of the current statement in the import file,
\(initially 1).

COUNT of inserted cells starts at 0.  TOTAL is the total number of statements
in IMPORT-FROM, used to show a running tally of the imported statements."
  (set-buffer import-from)
  (let ((cell-end-regexp " +\\([0-9][0-9a-z]*\\)\n\\(\n+\\|\\'\\)")
	contents start subtree-p end end-contents statement-level
	child-label)
    ;; While find cells at import-level or deeper ...
    (while (and (setq start (point))
		(re-search-forward cell-end-regexp nil t)
		(<= import-level
		   (setq statement-level
			 (klabel:level-alpha
			  (buffer-substring
			   (match-beginning 1) (match-end 1))))))
      (setq end-contents (match-beginning 0)
	    end (match-end 0))
      (goto-char start)
      (skip-chars-forward " ")
      (setq contents (kimport:unindent-region (point) end-contents))
      (goto-char end)
      (setq subtree-p (save-excursion
			(if (re-search-forward cell-end-regexp nil t)
			    (< statement-level
			       (klabel:level-alpha
				(buffer-substring
				 (match-beginning 1) (match-end 1)))))))
      (save-excursion
	(set-buffer output-to)
	;; Add the cell starting at point.
	(kview:add-cell klabel output-level contents nil t)
	(if subtree-p (setq child-label (klabel:child klabel)))
	(message "%d of %d statements converted..."
		 (setq count (1+ count)) total)
	(setq klabel (klabel:increment klabel)))
      ;;
      ;; Current buffer returns to `import-from' here.
      ;; Handle each sub-level through recursion.
      (if subtree-p
	  ;; Subtree exists so insert its cells.
	  (setq count
		(kimport:aug-post-statements
		 import-from output-to child-label (1+ output-level)
		 (1+ import-level) count total))))
    (goto-char start))
  count)

(defun kimport:copy-and-set-buffer (source)
  "Copy and untabify SOURCE, set copy buffer as current buffer for this command and return the copy buffer.
SOURCE may be a buffer name, a buffer or a file name.
If SOURCE buffer name begins with a space, it is not copied under the
assumption that it already has been.  If SOURCE is a koutline, it is not
copied since there is no need to copy it to import it."
  (setq source (set-buffer (or (get-buffer source)
			       (find-file-noselect source))))
  (let ((mode (or (if (boundp 'kotl-previous-mode) kotl-previous-mode)
		  major-mode))
	copy)
    (if (or (eq mode 'kotl-mode)
	    (eq ?\ (aref (buffer-name source) 0)))
	source
      ;; This buffer name format is used so that we can easily
      ;; extract any file name suffix from the buffer name.
      (setq copy (get-buffer-create
		  (concat " " (if (string-match ".+[|<]" (buffer-name))
				  (substring (buffer-name)
					     0 (1- (match-end 0)))
				(buffer-name)))))
      (set-buffer copy)
      ;; fundamental-mode can have an unusable value of paragraph-start so
      ;; use text-mode in such instances instead.
      (if (eq mode 'fundamental-mode)
	  (text-mode)
	(funcall mode))
      (setq buffer-read-only nil)
      (erase-buffer)
      (insert-buffer source)
      (untabify (point-min) (point-max))
      ;; Ensure buffer ends with a newline so that we don't miss the last
      ;; element during the import.
      (goto-char (point-max))
      (if (not (eq (preceding-char) ?\n)) (insert "\n"))
      (set-buffer-modified-p nil)
      copy)))

(defun kimport:initialize (output-to)
  "Setup to import elements into koutline OUTPUT-TO.
Return OUTPUT-TO buffer and set current buffer for the current command
to OUTPUT-TO.

OUTPUT-TO may be a buffer, buffer-name or file name.  If OUTPUT-TO exists
already, it must be a koutline or an error will be signaled.  For an existing
OUTPUT-TO, the text cells are inserted after the cell at point or after the
first cell for a newly loaded koutline.  If OUTPUT-TO is nil, the current
buffer is used.

If OUTPUT-TO is an existing koutline, the first cell imported will be added
as the successor of the current cell.  If an existing file is read in as
OUTPUT-TO within this function, point is left at the end of this buffer so
that imported cells will be appended to the buffer.  For a new file, this
means the first cell imported will become the first outline cell.

If a non-nil third argument, CHILDREN-P, is given to the caller of this
function and OUTPUT-TO contains at least one cell, then the imported cells
will be added as children of the cell where this function leaves point
\(either the current cell or for a newly read in outline, the last cell)."
  (let* ((output-existing-buffer-p
	  (if output-to
	     (or (get-buffer output-to) (get-file-buffer output-to))))
	 (output-exists-p
	  (if output-to
	     (or output-existing-buffer-p (file-exists-p output-to))
	   ;; current buffer will be used for output and it exists.
	   t)))
    (setq output-to (if output-to
			(or (get-buffer output-to)
			    (find-file-noselect output-to))
		      (current-buffer)))
    (set-buffer output-to)
    (if output-exists-p
	(if (eq major-mode 'kotl-mode)
	    (if (kotl-mode:buffer-empty-p)
		nil
	      ;; Make imported cells be appended if the output buffer was
	      ;; just read in.
	      (if output-existing-buffer-p nil (goto-char (point-max)))
	      (kotl-mode:to-valid-position))
	  (error
	   "(kimport:initialize): Second arg, %s, must be a koutline file."
	   (buffer-name output-to)))
      (if (eq major-mode 'kotl-mode)
	  nil
	(setq kview nil)
	(kotl-mode))
      (delete-region (point-min) (point-max))))
  output-to)

(defun kimport:kcells (import-from output-to klabel output-level
		       import-level count total)
  "Insert visible koutline cells (contents and attributes) from IMPORT-FROM into existing OUTPUT-TO. 

KLABEL is the label to use for the first imported cell.
OUTPUT-LEVEL is the level at which to insert the first cell.
IMPORT-LEVEL is the depth of the current cell in the import file,
\(initially 1).

COUNT of inserted cells starts at 0.  TOTAL is the total number of cells
in IMPORT-FROM, used to show a running tally of the imported cells."
  (set-buffer import-from)
  (goto-char (kcell-view:start))
  (let ((again t) contents subtree-p child-label)
    ;; While find cells at import-level or deeper ...
    (while (<= import-level (kcell-view:level))
      (setq subtree-p (kcell-view:child-p nil t)
	    contents (kcell-view:contents))
      (goto-char (kcell-view:end-contents))
      (save-excursion
	(set-buffer output-to)
	;; Add the cell starting at point.
	(kview:add-cell klabel output-level contents nil t)
	(if subtree-p (setq child-label (klabel:child klabel)))
	(message "%d of %d cells inserted..."
		 (setq count (1+ count)) total)
	(setq klabel (klabel:increment klabel)))
      ;;
      ;; Current buffer returns to `import-from' here.
      ;; Handle each sub-level through recursion.
      (if (and (setq again (kcell-view:next t)) subtree-p)
	  ;; Subtree exists so insert its cells.
	  (setq count
		(kimport:kcells
		 import-from output-to child-label (1+ output-level)
		 (1+ import-level) count total)))
      (if again nil (throw 'end count))))
  count)

(defun kimport:star-entries (import-from output-to klabel output-level
                             import-level count total)
  "Insert visible star outline entries from IMPORT-FROM into existing OUTPUT-TO. 

KLABEL is the label to use for the first imported entry.
OUTPUT-LEVEL is the level at which to insert the first entry.
IMPORT-LEVEL is the depth of the current entry in the import file,
\(initially 1).

COUNT of inserted entries starts at 0.  TOTAL is the total number of entries
in IMPORT-FROM, used to show a running tally of the imported entries."
  (set-buffer import-from)
  (let ((start (point))
	(rolo-entry-regexp "^[ \t]*\\(\\*+\\)")
	subtree-p end contents node-level child-label)
    ;; While find cells at import-level or deeper ...
    (while (and (re-search-forward rolo-entry-regexp nil t)
		(<= import-level
		    (setq node-level
			  (length
			   (buffer-substring
			    (match-beginning 1) (match-end 1))))))
      (skip-chars-forward " \t")
      (setq start (point)
	    end (rolo-to-entry-end)
	    subtree-p (if (looking-at rolo-entry-regexp)
			  (< node-level
			     (length (buffer-substring
				      (match-beginning 1) (match-end 1))))))
      (skip-chars-backward "\n\r")
      (setq contents (kimport:unindent-region start (point)))
      (save-excursion
	(set-buffer output-to)
	;; Add the cell starting at point.
	(kview:add-cell klabel output-level contents nil t)
	(if subtree-p (setq child-label (klabel:child klabel)))
	(message "%d of %d trees converted..."
		 (if (= node-level 1) (setq count (1+ count)) count)
		 total)
	(setq klabel (klabel:increment klabel)))
      ;;
      ;; Current buffer returns to `import-from' here.
      (goto-char end)
      ;;
      ;; Handle each sub-level through recursion.
      (if subtree-p
	  ;; Subtree exists so insert its cells.
	  (setq count
		(kimport:star-entries import-from output-to child-label
				      (1+ output-level) (1+ import-level)
				      count total))))
    (goto-char start))
  count)

(defun kimport:text-paragraphs (import-from output-to klabel
			        output-level count total)
  "Insert text paragraphs from IMPORT-FROM into existing OUTPUT-TO.
First cell is inserted with KLABEL at OUTPUT-LEVEL, as the sibling of the
previous cell, with the COUNT of inserted paragraphs starting at 0.  TOTAL is
the total number of paragraphs in IMPORT-FROM, used to show a running tally
of the imported paragraphs.

The variable, `paragraph-start' is used to determine paragraphs."
  (set-buffer import-from)
  (let* ((count 0) start end contents)
    ;; Next line is needed when importing into an existing kview.
    (goto-char (point-min))
    ;; Move past blank lines at point.
    (skip-chars-forward " \t\n\r")
    (beginning-of-line)
    (while (and (setq start (point))
		(progn (while (and (not (looking-at paragraph-start))
				   (zerop (forward-line 1))))
		       t)
		(if (looking-at paragraph-start)
		    (setq end (goto-char (match-end 0))))
		(/= start end))
      (setq contents (kimport:unindent-region start end))
      (set-buffer output-to)
      ;; Add the cell starting at point.
      (kview:add-cell klabel output-level contents nil t)
      (setq count (1+ count))
      (message "%d of %d paragraphs converted..."
	       count total)
      (setq klabel (klabel:increment klabel))
      (set-buffer import-from)
      (goto-char end)
      ;; Move past blank lines separating paragraphs.
      (skip-chars-forward " \t\n\r")
      (beginning-of-line))
    (message "%d of %d paragraphs converted" count total)
    count))

(defun kimport:unindent-region (start end)
  "Calculate indent based upon the second line within the region START to END.
Remove the indent and return the remaining region as a string."
  (save-excursion
    (let (indent-regexp)
      (goto-char start)
      ;; Remove leading indent from lines in paragraph.  Base paragraph
      ;; indent on the 2nd paragraph line since the first line might be
      ;; further indented or outdented.
      (setq indent-regexp
	    (if (re-search-forward "[\n\r][ \t]+" end t)
		(concat "^" (make-string (current-column) ?\ ))))
      (if indent-regexp
	  (hypb:replace-match-string
			  indent-regexp (buffer-substring start end) "" t)
	(buffer-substring start end)))))

(provide 'kimport)