Initial Commit
[packages] / xemacs-packages / hyperbole / kotl / kimport.el
1 ;;; kimport.el --- Convert and insert other outline file formats into koutlines.
2
3 ;; Copyright (C)  Free Software Foundation, Inc.
4 ;; Developed with support from Motorola Inc.
5
6 ;; Author: Bob Weiner, Brown U.
7 ;;         Kellie Clark
8 ;; Maintainer: Mats Lidell <matsl@contactor.se>
9 ;; Keywords: data, outlines, wp
10
11 ;; This file is part of GNU Hyperbole.
12
13 ;; GNU Hyperbole is free software; you can redistribute it and/or
14 ;; modify it under the terms of the GNU General Public License as
15 ;; published by the Free Software Foundation; either version 3, or (at
16 ;; your option) any later version.
17
18 ;; GNU Hyperbole is distributed in the hope that it will be useful,
19 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21 ;; General Public License for more details.
22
23 ;; You should have received a copy of the GNU General Public License
24 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
25 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
26 ;; Boston, MA 02110-1301, USA.
27
28 ;;; Commentary:
29
30 ;;; Code:
31
32 ;; kfile.el requires kotl-mode.el which requires kimport.el.
33 (require 'wrolo)
34
35 ;;;
36 ;;; Public variables
37 ;;;
38
39 ;;  kimport:mode-alist and kimport:suffix-alist are defined in
40 ;;  "../hyperbole.el".
41
42 ;;;
43 ;;; Public functions
44 ;;;
45
46 ;;;###autoload
47 (defun kimport:file (import-from output-to &optional children-p)
48   "Import a buffer or file IMPORT-FROM into the koutline in buffer or file OUTPUT-TO.
49
50 Any suffix in IMPORT-FROM's buffer name is used to determine the type of
51 importation.  All others are imported as text, one paragraph per cell.
52
53 See the documentation for the variable, `kimport:suffix-alist' for
54 information on specific importation formats."
55   (interactive "FImport from buffer/file: \nFInsert into koutline buffer/file: \nP")
56   (let ((import-buf-name
57          (cond ((or (bufferp import-from)
58                     (get-buffer import-from))
59                 (buffer-name (get-buffer import-from)))
60                ((get-file-buffer import-from)
61                 (buffer-name (get-file-buffer import-from)))
62                ((stringp import-from)
63                 (file-name-nondirectory import-from))
64                (t (error "(kimport:buffer): `%s' is an invalid `import-from' argument"))))
65         (function))
66
67     (set-buffer import-buf-name)
68     (if (setq function (cdr (assq major-mode kimport:mode-alist)))
69         nil
70       (let ((import-suffix (if (string-match "\\..+\\'" import-buf-name)
71                                (match-string 0 import-buf-name)))
72             (suffix-alist kimport:suffix-alist)
73             suffix-regexp)
74         (while (and import-suffix suffix-alist)
75           (setq suffix-regexp (car (car suffix-alist))
76                 function (cdr (car suffix-alist))
77                 suffix-alist (cdr suffix-alist))
78           (if (string-match suffix-regexp import-suffix)
79               nil
80             (setq function nil)))
81         (if function nil (setq function (cdr (assq t kimport:mode-alist))))))
82     (funcall function import-from output-to children-p)))
83
84 ;;; Augment right-side numbered files, blank line between cells
85 ;;;
86
87 ;;;###autoload
88 (defun kimport:aug-post-outline (import-from output-to &optional children-p)
89   "Insert Augment outline statements from IMPORT-FROM into koutline OUTPUT-TO.
90 Displays and leaves point in OUTPUT-TO.  See documentation for
91 `kimport:initialize' for valid values of IMPORT-FROM and OUTPUT-TO and for
92 an explanation of where imported cells are placed.
93
94 If OUTPUT-TO is a new koutline, the first statement inserted will be the
95 first cell.  Otherwise, it will be the successor of the current cell.
96
97 Each statement to be imported is delimited by an Augment relative id at the
98 end of the statement.  \"1\" = level 1, \"1a\" = level 2 in outline and so
99 on."
100   (interactive "FImport from Augment post-numbered buffer/file: \nFBuffer/file to insert cells into: \nP")
101   (let ((output-level 1) (klabel "1")
102         initially-empty-output no-renumber orig-point count total)
103     ;; Don't change the order of import-from and output-to inits here.
104     (setq import-from (kimport:copy-and-set-buffer import-from)
105           output-to (kimport:initialize output-to)
106           orig-point (point)
107           initially-empty-output (zerop (- (point-max) (point-min)))
108           no-renumber (or initially-empty-output
109                           (not (if children-p
110                                    (kcell-view:child-p)
111                                  (kcell-view:sibling-p)))))
112
113     (if (eq import-from output-to)
114         (error "(kimport:aug-post-outline): Import and output buffers may not be the same."))
115
116     (set-buffer import-from)
117     (show-all)
118     (save-excursion
119       (goto-char (point-min))
120       ;; Total number of Augement statements.
121       (setq total (read (count-matches
122                          " +\\([0-9][0-9a-z]*\\)\n\\(\n\\|\\'\\)")))
123       (if initially-empty-output
124           nil
125         ;; Insert first cell as sibling of current cell.
126         (set-buffer output-to)
127         (if children-p
128             ;; Insert as children.
129             (progn (setq klabel (klabel:child (kcell-view:label))
130                          output-level (klabel:level klabel))
131                    ;; Move to end of this cell since cell insertion will
132                    ;; occur at point.
133                    (goto-char (kcell-view:end)))
134         ;; Insert as successors.
135         (setq klabel (klabel:increment (kcell-view:label))
136               output-level (klabel:level klabel))
137         ;; Move to start of line of next tree since cell insertion will occur
138         ;; at point.
139         (goto-char (kotl-mode:tree-end))))
140       (setq count (kimport:aug-post-statements
141                    import-from output-to klabel output-level 1 0 total)))
142     (pop-to-buffer output-to)
143     (kfile:narrow-to-kcells)
144     (if no-renumber nil (klabel-type:update-labels klabel))
145     (goto-char orig-point)
146     (if (kotl-mode:buffer-empty-p)
147         nil
148       (kotl-mode:to-valid-position))
149     (message "Imported %d of %d Augment statements." count total)))
150
151 ;;;
152 ;;; Emacs outliner style files, leading '*' cell delimiters
153 ;;;
154
155 ;;;###autoload
156 (defun kimport:star-outline (import-from output-to &optional children-p)
157   "Insert star outline nodes from IMPORT-FROM into koutline OUTPUT-TO.
158 Displays and leaves point in OUTPUT-TO.  See documentation for
159 `kimport:initialize' for valid values of IMPORT-FROM and OUTPUT-TO and for
160 an explanation of where imported cells are placed.
161
162 \"* \" = level 1, \"** \" = level 2 in outline and so on."
163   (interactive "FImport from star delimited cells buffer/file: \nFBuffer/file to insert cells into: \nP")
164   (let ((output-level 1) (klabel "1")
165         initially-empty-output no-renumber orig-point count total) 
166     ;; Don't change the order of import-from and output-to inits here.
167     (setq import-from (kimport:copy-and-set-buffer import-from)
168           output-to (kimport:initialize output-to)
169           orig-point (point)
170           initially-empty-output (zerop (- (point-max) (point-min)))
171           no-renumber (or initially-empty-output
172                           (not (if children-p
173                                    (kcell-view:child-p)
174                                  (kcell-view:sibling-p)))))
175
176     (if (eq import-from output-to)
177         (error "(kimport:star-outline): Import and output buffers may not be the same."))
178
179     (set-buffer import-from)
180     (show-all)
181     (save-excursion
182       (goto-char (point-min))
183       ;; If initial text in buffer is not an star outline node, add a star to
184       ;; make it one, so it is not deleted from the import.
185       (if (not (looking-at "[ \t]*\\*"))
186           (insert "* "))
187       (goto-char (point-min))
188       ;; Total number of top-level cells.
189       (setq total (read (count-matches "^[ \t]*\\*[ \t\n]")))
190       (if initially-empty-output
191           nil
192         ;; Insert first cell as sibling of current cell.
193         (set-buffer output-to)
194         (if children-p
195             ;; Insert as children.
196             (progn (setq klabel (klabel:child (kcell-view:label))
197                          output-level (klabel:level klabel))
198                    ;; Move to end of this cell since cell insertion will
199                    ;; occur at point.
200                    (goto-char (kcell-view:end)))
201         ;; Insert as successors.
202         (setq klabel (klabel:increment (kcell-view:label))
203               output-level (klabel:level klabel))
204         ;; Move to start of line of next tree since cell insertion will occur
205         ;; at point.
206         (goto-char (kotl-mode:tree-end))))
207       (setq count (kimport:star-entries
208                    import-from output-to klabel output-level 1 0 total)))
209     (pop-to-buffer output-to)
210     (kfile:narrow-to-kcells)
211     (if no-renumber nil (klabel-type:update-labels klabel))
212     (goto-char orig-point)
213     (if (kotl-mode:buffer-empty-p)
214         nil
215       (kotl-mode:to-valid-position))
216     (message "Imported %d of %d star outline trees." count total)))
217
218 ;;;
219 ;;; Generic text file import or koutline insertion.
220 ;;;
221
222 ;;;###autoload
223 (defun kimport:text (import-from output-to &optional children-p)
224   "Insert text paragraphs from IMPORT-FROM into koutline OUTPUT-TO.
225 Displays and leaves point in OUTPUT-TO.  See documentation for
226 `kimport:initialize' for valid values of IMPORT-FROM and OUTPUT-TO and for
227 an explanation of where imported cells are placed.
228
229 Text paragraphs are imported as a sequence of same level cells.  Koutlines
230 are imported with their structure intact.
231
232 The variable, 'paragraph-start,' is used to determine paragraphs."
233   (interactive "FImport from text/koutline buffer/file: \nFInsert cells into koutline buffer/file: \nP")
234   (let ((klabel "1") (output-level 1) (count 0) initially-empty-output
235         no-renumber orig-point total)
236     ;; Don't change the order of import-from and output-to inits here.
237     (setq import-from (kimport:copy-and-set-buffer import-from)
238           output-to (kimport:initialize output-to)
239           orig-point (point)
240           initially-empty-output (zerop (- (point-max) (point-min)))
241           no-renumber (or initially-empty-output
242                           (not (if children-p
243                                    (kcell-view:child-p)
244                                  (kcell-view:sibling-p)))))
245
246     (if (eq import-from output-to)
247         (error "(kimport:text): Import and output buffers may not be the same."))
248
249     (set-buffer import-from)
250     (let ((kotl-import (eq major-mode 'kotl-mode))
251           visible-cells)
252       (save-excursion
253         (if initially-empty-output
254             nil
255           ;; Insert first cell as sibling of current cell.
256           (set-buffer output-to)
257           (if children-p
258               ;; Insert as children.
259               (progn (setq klabel (klabel:child (kcell-view:label))
260                            output-level (klabel:level klabel))
261                      ;; Move to end of this cell since cell insertion will
262                      ;; occur at point.
263                      (goto-char (kcell-view:end)))
264             ;; Insert as successors.
265             (setq klabel (klabel:increment (kcell-view:label))
266                   output-level (klabel:level klabel))
267             ;; Move to start of line of next tree since cell insertion will occur
268             ;; at point.
269             (goto-char (kotl-mode:tree-end)))
270           (set-buffer import-from))
271
272         (if kotl-import
273             ;; Importing from a koutline, so handle specially.
274             (progn (kotl-mode:beginning-of-buffer)
275                    ;; Total number of cells.
276                    (setq total (read (count-matches "[\n\r][\n\r]"))
277                          visible-cells (read (count-matches "\n\n"))
278                          count (save-excursion
279                                  ;; Incredible non-local exit to ensure that
280                                  ;; recursion ends at the right time.
281                                  (catch 'end
282                                    (kimport:kcells import-from output-to klabel
283                                                    output-level 1
284                                                    count total)))))
285
286           (show-all)
287           (goto-char (point-min))
288           ;; Total number of paragraphs.
289           (setq total (read (count-matches paragraph-start))
290                 count (kimport:text-paragraphs import-from output-to klabel
291                                                output-level count total))))
292       (pop-to-buffer output-to)
293       (kfile:narrow-to-kcells)
294       (if no-renumber nil (klabel-type:update-labels klabel))
295       (goto-char orig-point)
296       (if (kotl-mode:buffer-empty-p)
297           nil
298         (kotl-mode:to-valid-position))
299       (if kotl-import
300           (message "Imported %d of %d visible cells from a %d cell outline."
301                    count visible-cells total)
302         (message "Imported %d of %d paragraphs." count total)))))
303
304 ;;;
305 ;;; Private functions - Don't call these functions from outside of this
306 ;;; module or you may misuse them and cause data corruption.
307 ;;;
308
309 (defun kimport:aug-label-lessp (label1 label2)
310   "Return non-nil iff Augment-style LABEL1 is less than LABEL2."
311   (let ((lev1 (klabel:level-alpha label1))
312         (lev2 (klabel:level-alpha label2)))
313     (cond ((< lev1 lev2))
314           ((= lev1 lev2) (string-lessp label1 label2))
315           (t nil))))
316
317 (defun kimport:aug-post-statements (import-from output-to klabel output-level
318                                     import-level count total)
319   "Insert post-numbered Augment statements (contents only) from IMPORT-FROM into existing OUTPUT-TO. 
320
321 KLABEL is the label to use for the first imported statement.
322 OUTPUT-LEVEL is the level at which to insert the first statement.
323 IMPORT-LEVEL is the depth of the current statement in the import file,
324 \(initially 1).
325
326 COUNT of inserted cells starts at 0.  TOTAL is the total number of statements
327 in IMPORT-FROM, used to show a running tally of the imported statements."
328   (set-buffer import-from)
329   (let ((cell-end-regexp " +\\([0-9][0-9a-z]*\\)\n\\(\n+\\|\\'\\)")
330         contents start subtree-p end end-contents statement-level
331         child-label)
332     ;; While find cells at import-level or deeper ...
333     (while (and (setq start (point))
334                 (re-search-forward cell-end-regexp nil t)
335                 (<= import-level
336                    (setq statement-level
337                          (klabel:level-alpha
338                           (buffer-substring
339                            (match-beginning 1) (match-end 1))))))
340       (setq end-contents (match-beginning 0)
341             end (match-end 0))
342       (goto-char start)
343       (skip-chars-forward " ")
344       (setq contents (kimport:unindent-region (point) end-contents))
345       (goto-char end)
346       (setq subtree-p (save-excursion
347                         (if (re-search-forward cell-end-regexp nil t)
348                             (< statement-level
349                                (klabel:level-alpha
350                                 (buffer-substring
351                                  (match-beginning 1) (match-end 1)))))))
352       (save-excursion
353         (set-buffer output-to)
354         ;; Add the cell starting at point.
355         (kview:add-cell klabel output-level contents nil t)
356         (if subtree-p (setq child-label (klabel:child klabel)))
357         (message "%d of %d statements converted..."
358                  (setq count (1+ count)) total)
359         (setq klabel (klabel:increment klabel)))
360       ;;
361       ;; Current buffer returns to `import-from' here.
362       ;; Handle each sub-level through recursion.
363       (if subtree-p
364           ;; Subtree exists so insert its cells.
365           (setq count
366                 (kimport:aug-post-statements
367                  import-from output-to child-label (1+ output-level)
368                  (1+ import-level) count total))))
369     (goto-char start))
370   count)
371
372 (defun kimport:copy-and-set-buffer (source)
373   "Copy and untabify SOURCE, set copy buffer as current buffer for this command and return the copy buffer.
374 SOURCE may be a buffer name, a buffer or a file name.
375 If SOURCE buffer name begins with a space, it is not copied under the
376 assumption that it already has been.  If SOURCE is a koutline, it is not
377 copied since there is no need to copy it to import it."
378   ;; This buffer name format is used so that we can easily
379   ;; extract any file name suffix from the buffer name.
380   (setq source (set-buffer (or (get-buffer source)
381                                (find-file-noselect source))))
382   (let ((mode (or (if (boundp 'kotl-previous-mode) kotl-previous-mode)
383                   major-mode))
384         copy)
385     (if (or (eq mode 'kotl-mode)
386             (= ?\ (aref (buffer-name source) 0)))
387         source
388       (setq copy (get-buffer-create
389                   (concat " " (if (string-match ".+[|<]" (buffer-name))
390                                   (substring (buffer-name)
391                                              0 (1- (match-end 0)))
392                                 (buffer-name)))))
393       (set-buffer copy)
394       (setq buffer-read-only nil
395             major-mode mode)
396       (erase-buffer)
397       (insert-buffer source)
398       (untabify (point-min) (point-max))
399       ;; Ensure buffer ends with a newline so that we don't miss the last
400       ;; element during the import.
401       (goto-char (point-max))
402       (if (/= (preceding-char) ?\n) (insert "\n"))
403       (set-buffer-modified-p nil)
404       copy)))
405
406 (defun kimport:initialize (output-to)
407   "Setup to import elements into koutline OUTPUT-TO.
408 Return OUTPUT-TO buffer and set current buffer for the current command
409 to OUTPUT-TO.
410
411 OUTPUT-TO may be a buffer, buffer-name or file name.  If OUTPUT-TO exists
412 already, it must be a koutline or an error will be signaled.  For an existing
413 OUTPUT-TO, the text cells are inserted after the cell at point or after the
414 first cell for a newly loaded koutline.  If OUTPUT-TO is nil, the current
415 buffer is used.
416
417 If OUTPUT-TO is an existing koutline, the first cell imported will be added
418 as the successor of the current cell.  If an existing file is read in as
419 OUTPUT-TO within this function, point is left at the end of this buffer so
420 that imported cells will be appended to the buffer.  For a new file, this
421 means the first cell imported will become the first outline cell.
422
423 If a non-nil third argument, CHILDREN-P, is given to the caller of this
424 function and OUTPUT-TO contains at least one cell, then the imported cells
425 will be added as children of the cell where this function leaves point
426 \(either the current cell or for a newly read in outline, the last cell)."
427   (let* ((output-existing-buffer-p
428           (if output-to
429              (or (get-buffer output-to) (get-file-buffer output-to))))
430          (output-exists-p
431           (if output-to
432              (or output-existing-buffer-p (file-exists-p output-to))
433            ;; current buffer will be used for output and it exists.
434            t)))
435     (setq output-to (if output-to
436                         (or (get-buffer output-to)
437                             (find-file-noselect output-to))
438                       (current-buffer)))
439     (set-buffer output-to)
440     (if output-exists-p
441         (if (eq major-mode 'kotl-mode)
442             (if (kotl-mode:buffer-empty-p)
443                 nil
444               ;; Make imported cells be appended if the output buffer was
445               ;; just read in.
446               (if output-existing-buffer-p nil (goto-char (point-max)))
447               (kotl-mode:to-valid-position))
448           (error
449            "(kimport:initialize): Second arg, %s, must be a koutline file."
450            (buffer-name output-to)))
451       (if (eq major-mode 'kotl-mode)
452           nil
453         (setq kview nil)
454         (kotl-mode))
455       (delete-region (point-min) (point-max))))
456   output-to)
457
458 (defun kimport:kcells (import-from output-to klabel output-level
459                        import-level count total)
460   "Insert visible koutline cells (contents and attributes) from IMPORT-FROM into existing OUTPUT-TO. 
461
462 KLABEL is the label to use for the first imported cell.
463 OUTPUT-LEVEL is the level at which to insert the first cell.
464 IMPORT-LEVEL is the depth of the current cell in the import file,
465 \(initially 1).
466
467 COUNT of inserted cells starts at 0.  TOTAL is the total number of cells
468 in IMPORT-FROM, used to show a running tally of the imported cells."
469   (set-buffer import-from)
470   (goto-char (kcell-view:start))
471   (let ((again t) contents subtree-p child-label)
472     ;; While find cells at import-level or deeper ...
473     (while (<= import-level (kcell-view:level))
474       (setq subtree-p (kcell-view:child-p nil t)
475             contents (kcell-view:contents))
476       (goto-char (kcell-view:end-contents))
477       (save-excursion
478         (set-buffer output-to)
479         ;; Add the cell starting at point.
480         (kview:add-cell klabel output-level contents nil t)
481         (if subtree-p (setq child-label (klabel:child klabel)))
482         (message "%d of %d cells inserted..."
483                  (setq count (1+ count)) total)
484         (setq klabel (klabel:increment klabel)))
485       ;;
486       ;; Current buffer returns to `import-from' here.
487       ;; Handle each sub-level through recursion.
488       (if (and (setq again (kcell-view:next t)) subtree-p)
489           ;; Subtree exists so insert its cells.
490           (setq count
491                 (kimport:kcells
492                  import-from output-to child-label (1+ output-level)
493                  (1+ import-level) count total)))
494       (if again nil (throw 'end count))))
495   count)
496
497 (defun kimport:star-entries (import-from output-to klabel output-level
498                              import-level count total)
499   "Insert visible star outline entries from IMPORT-FROM into existing OUTPUT-TO. 
500
501 KLABEL is the label to use for the first imported entry.
502 OUTPUT-LEVEL is the level at which to insert the first entry.
503 IMPORT-LEVEL is the depth of the current entry in the import file,
504 \(initially 1).
505
506 COUNT of inserted entries starts at 0.  TOTAL is the total number of entries
507 in IMPORT-FROM, used to show a running tally of the imported entries."
508   (set-buffer import-from)
509   (let ((start (point))
510         (rolo-entry-regexp "^[ \t]*\\(\\*+\\)")
511         subtree-p end contents node-level child-label)
512     ;; While find cells at import-level or deeper ...
513     (while (and (re-search-forward rolo-entry-regexp nil t)
514                 (<= import-level
515                     (setq node-level
516                           (length
517                            (buffer-substring
518                             (match-beginning 1) (match-end 1))))))
519       (skip-chars-forward " \t")
520       (setq start (point)
521             end (rolo-to-entry-end)
522             subtree-p (if (looking-at rolo-entry-regexp)
523                           (< node-level
524                              (length (buffer-substring
525                                       (match-beginning 1) (match-end 1))))))
526       (skip-chars-backward "\n\r")
527       (setq contents (kimport:unindent-region start (point)))
528       (save-excursion
529         (set-buffer output-to)
530         ;; Add the cell starting at point.
531         (kview:add-cell klabel output-level contents nil t)
532         (if subtree-p (setq child-label (klabel:child klabel)))
533         (message "%d of %d trees converted..."
534                  (if (= node-level 1) (setq count (1+ count)) count)
535                  total)
536         (setq klabel (klabel:increment klabel)))
537       ;;
538       ;; Current buffer returns to `import-from' here.
539       (goto-char end)
540       ;;
541       ;; Handle each sub-level through recursion.
542       (if subtree-p
543           ;; Subtree exists so insert its cells.
544           (setq count
545                 (kimport:star-entries import-from output-to child-label
546                                       (1+ output-level) (1+ import-level)
547                                       count total))))
548     (goto-char start))
549   count)
550
551 (defun kimport:text-paragraphs (import-from output-to klabel
552                                 output-level count total)
553   "Insert text paragraphs from IMPORT-FROM into existing OUTPUT-TO.
554 First cell is inserted with KLABEL at OUTPUT-LEVEL, as the sibling of the
555 previous cell, with the COUNT of inserted paragraphs starting at 0.  TOTAL is
556 the total number of paragraphs in IMPORT-FROM, used to show a running tally
557 of the imported paragraphs.
558
559 The variable, 'paragraph-start' is used to determine paragraphs."
560   (set-buffer import-from)
561   (let* ((count 0) start end contents)
562     ;; Next line is needed when importing into an existing kview.
563     (goto-char (point-min))
564     ;; Move past blank lines at point.
565     (skip-chars-forward " \t\n\r")
566     (beginning-of-line)
567     (while (and (setq start (point)
568                       end (re-search-forward paragraph-start nil t))
569                 (/= start end))
570       (setq contents (kimport:unindent-region start end))
571       (set-buffer output-to)
572       ;; Add the cell starting at point.
573       (kview:add-cell klabel output-level contents nil t)
574       (setq count (1+ count))
575       (message "%d of %d paragraphs converted..."
576                count total)
577       (setq klabel (klabel:increment klabel))
578       (set-buffer import-from)
579       (goto-char end)
580       ;; Move past blank lines separating paragraphs.
581       (skip-chars-forward " \t\n\r")
582       (beginning-of-line))
583     (message "%d of %d paragraphs converted" count total)
584     count))
585
586 (defun kimport:unindent-region (start end)
587   "Calculate indent based upon the second line within the region START to END.
588 Remove the indent and return the remaining region as a string."
589   (save-excursion
590     (let (indent-regexp)
591       (goto-char start)
592       ;; Remove leading indent from lines in paragraph.  Base paragraph
593       ;; indent on the 2nd paragraph line since the first line might be
594       ;; further indented or outdented.
595       (setq indent-regexp
596             (if (re-search-forward "[\n\r][ \t]+" end t)
597                 (concat "^" (make-string (current-column) ?\ ))))
598       (if indent-regexp
599           (hypb:replace-match-string
600                           indent-regexp (buffer-substring start end) "" t)
601         (buffer-substring start end)))))
602
603 (provide 'kimport)
604
605
606 ;;; kimport.el ends here