unofficial mirror of help-gnu-emacs@gnu.org
 help / color / mirror / Atom feed
* New to elisp, learning by doing
@ 2003-02-16 22:45 John Rabkin
  2003-02-17  2:03 ` Christopher J. White
                   ` (2 more replies)
  0 siblings, 3 replies; 9+ messages in thread
From: John Rabkin @ 2003-02-16 22:45 UTC (permalink / raw)


I've decided to learn some elisp to ease some of my work (I edit allot of
HTML and use emacs exclusively). I have a method for exploring new
languages: I set myself a simple goal such as a program that does a small
task and try to learn about the language through hacking that program.
If the simple program ends up being useful then I'm even happier.

My goal in elisp is a .el that writes a table of contents from HTML
headers. The program would search for header tags in the buffer beginning
at point and write them in order one under the other.

After fighting with elisp for a couple of weeks in my spare time I turn to
anyone who can give me a clue or a push in the right direction. This is
what I have:

 (defun html-yank-header ()
  "Copies and yanks HTML headers"
  (interactive)
  (save-excursion
    (setq start_p (- (re-search-forward "\<h[12345]*\>") 4)) 
    (setq end_p (re-search-forward "\<\/h[12345]\>")) 
    (copy-region-as-kill start_p end_p)
    )
  (yank)
  )

This grabs the header closest to point and copies it to point. Now I need
the program to recurse N times where N is the number of header tags in the
buffer.

I do not expect nor do I desire a solution. I would ideally like to be
pointed in the right direction. My experiments with while loops turn out
ungainly and to big to seem right.

Thank you in advance for anyone who took the time to read this.

-- 
"Cut your own wood and it will warm you twice"
	Regards, Yoni Rabkin

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: New to elisp, learning by doing
  2003-02-16 22:45 New to elisp, learning by doing John Rabkin
@ 2003-02-17  2:03 ` Christopher J. White
  2003-02-17  7:16 ` Kai Großjohann
  2003-02-17 18:47 ` Kevin Rodgers
  2 siblings, 0 replies; 9+ messages in thread
From: Christopher J. White @ 2003-02-17  2:03 UTC (permalink / raw)


>>>>> "john" == John Rabkin <yoni-r@actcom.com> writes:

john> After fighting with elisp for a couple of weeks in my spare time
john> I turn to anyone who can give me a clue or a push in the right
john> direction. This is what I have:

john>  (defun html-yank-header ()
john>   "Copies and yanks HTML headers"
john>   (interactive)
john>   (save-excursion
john>     (setq start_p (- (re-search-forward "\<h[12345]*\>") 4)) 
john>     (setq end_p (re-search-forward "\<\/h[12345]\>")) 
john>     (copy-region-as-kill start_p end_p)
john>     )
john>   (yank)
john>   )

john> This grabs the header closest to point and copies it to
john> point. Now I need the program to recurse N times where N is the
john> number of header tags in the buffer.

Despite your experience with loops, I would use certainly
use one for this case.  I don't really see how you could do
it without a loop unless you know how many times 
to search.  Here's a few things to investigate:

 - iterate over the return value of (re-search-forward) passing t
   as the NOERROR argument...

   (while (re-search-forward "..." nil t)
      ...
    )

 - use markers to save positions: (make-marker), (set-marker) and
   (marker-position)  You can bounce back and forth from the
   TOC point to the search point.  You need to use markers
   for this, as just using (point) won't work if you are inserting
   text at the beginning of the file because (point) is an offset,
   not a relative reference.

...cj

-- 
------------------------
-- Christopher J. White                                    
--
-- chris @
--   grierwhite.com
------------------------

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: New to elisp, learning by doing
  2003-02-16 22:45 New to elisp, learning by doing John Rabkin
  2003-02-17  2:03 ` Christopher J. White
@ 2003-02-17  7:16 ` Kai Großjohann
  2003-02-17  9:27   ` Hannu Koivisto
                     ` (3 more replies)
  2003-02-17 18:47 ` Kevin Rodgers
  2 siblings, 4 replies; 9+ messages in thread
From: Kai Großjohann @ 2003-02-17  7:16 UTC (permalink / raw)


"John Rabkin" <yoni-r@actcom.com> writes:

> My goal in elisp is a .el that writes a table of contents from HTML
> headers. The program would search for header tags in the buffer beginning
> at point and write them in order one under the other.

I would collect the header tags and/or their contents in a list of
strings, I think.  Then, after reaching the end of the buffer, I'd
write them out near the beginning of the buffer.

(let ((toc nil))
  (goto-char (point-max))
  (while (re-search-backward REGEXP nil t)
    (setq toc (cons TOC-ENTRY toc)))
  INSERT-TOC)

Note that I'm searching backwards because the entries are added to
the beginning of the list.  If searching backwards proves
inconvenient, then you could reverse the list (using nreverse) after
you're done.  Or you implement a little queue.  Queues are not a
standard Lisp datatype, I'm afraid.  (Or is there an Emacs Lisp
package for this?)
-- 
A turnip curses Elvis

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: New to elisp, learning by doing
  2003-02-17  7:16 ` Kai Großjohann
@ 2003-02-17  9:27   ` Hannu Koivisto
  2003-02-18  8:02     ` Kai Großjohann
  2003-02-17 18:24   ` Ehud Karni
                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 9+ messages in thread
From: Hannu Koivisto @ 2003-02-17  9:27 UTC (permalink / raw)


kai.grossjohann@uni-duisburg.de (Kai Großjohann) writes:

> "John Rabkin" <yoni-r@actcom.com> writes:
>
>> My goal in elisp is a .el that writes a table of contents from HTML
>> headers. The program would search for header tags in the buffer beginning
>> at point and write them in order one under the other.
>
> I would collect the header tags and/or their contents in a list of
> strings, I think.  Then, after reaching the end of the buffer, I'd
> write them out near the beginning of the buffer.
>
> (let ((toc nil))
>   (goto-char (point-max))
>   (while (re-search-backward REGEXP nil t)
>     (setq toc (cons TOC-ENTRY toc)))

I suggest you look up `push'.

>   INSERT-TOC)
>
> Note that I'm searching backwards because the entries are added to
> the beginning of the list.  If searching backwards proves
> inconvenient, then you could reverse the list (using nreverse) after
> you're done.  Or you implement a little queue.  Queues are not a

You could do those things if you were a C programmer who only has
primitive iteration constructs like while and for.

(require 'cl)

(let ((toc (loop while (re-search-forward regexp nil t)
                 collect toc-entry)))
  (move-to-wherever-you-want-toc)
  (loop for entry in toc
        do (insert (format entry-and-maybe-other-stuff))))

-- 
Hannu

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: New to elisp, learning by doing
  2003-02-17  7:16 ` Kai Großjohann
  2003-02-17  9:27   ` Hannu Koivisto
@ 2003-02-17 18:24   ` Ehud Karni
       [not found]   ` <mailman.2034.1045507046.21513.help-gnu-emacs@gnu.org>
  2003-02-18 10:26   ` Oliver Scholz
  3 siblings, 0 replies; 9+ messages in thread
From: Ehud Karni @ 2003-02-17 18:24 UTC (permalink / raw)
  Cc: Gnu Emacs help

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On Mon, 17 Feb 2003 08:16:51 +0100, kai.grossjohann@uni-duisburg.de wrote:
> 
> > My goal in elisp is a .el that writes a table of contents from HTML
> > headers. The program would search for header tags in the buffer beginning
> > at point and write them in order one under the other.
> 
> I would collect the header tags and/or their contents in a list of
> strings, I think.  Then, after reaching the end of the buffer, I'd
> write them out near the beginning of the buffer.
> 
> (let ((toc nil))
>   (goto-char (point-max))
>   (while (re-search-backward REGEXP nil t)
>     (setq toc (cons TOC-ENTRY toc)))
>   INSERT-TOC)

I would do it with strings in a straight forward logic:

(let ((toc "")   ;; this the same as nil (but gives its usage intent)
      (RGXP "<[hH][1-6]>.*</[hH][1-6]>"))
   (goto-char (point-min))
   (while (re-search-forward RGXP nil t)
          (setq toc (concat toc (match-string 0) "\n")))
   (goto-char (point-min))
   (insert toc))

Please note:
1. The search will not cross lines (it will not find a header if the
   opening tag is on one line and the closing tag on another line).
2. The search does check that the opening and closing tags are the 
   same level (e.g. <H1> .... </H3>).

If you want to overcome these problem its is better to do the search
in 2 steps, finding the opening tag and THEN searching its MATCHING
closing tag.

Ehud.


- -- 
 Ehud Karni           Tel: +972-3-7966-561  /"\
 Mivtach - Simon      Fax: +972-3-7966-667  \ /  ASCII Ribbon Campaign
 Insurance agencies   (USA) voice mail and   X   Against   HTML   Mail
 http://www.mvs.co.il  FAX:  1-815-5509341  / \
 mailto:ehud@unix.mvs.co.il                  Better  Safe  Than  Sorry
-----BEGIN PGP SIGNATURE-----
Comment: use http://www.keyserver.net/ to get my key (and others)

iD8DBQE+USjSLFvTvpjqOY0RAk0hAJ4xQeBTTLVVjFpOpxRwigui+ht6egCghT6i
HquQCCKskFDxaLE3tNJkaYE=
=iicu
-----END PGP SIGNATURE-----

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: New to elisp, learning by doing
  2003-02-16 22:45 New to elisp, learning by doing John Rabkin
  2003-02-17  2:03 ` Christopher J. White
  2003-02-17  7:16 ` Kai Großjohann
@ 2003-02-17 18:47 ` Kevin Rodgers
  2 siblings, 0 replies; 9+ messages in thread
From: Kevin Rodgers @ 2003-02-17 18:47 UTC (permalink / raw)


John Rabkin wrote:

>  (defun html-yank-header ()
>   "Copies and yanks HTML headers"
>   (interactive)
>   (save-excursion
>     (setq start_p (- (re-search-forward "\<h[12345]*\>") 4)) 
>     (setq end_p (re-search-forward "\<\/h[12345]\>")) 
>     (copy-region-as-kill start_p end_p)
>     )
>   (yank)
>   )


I would avoid using the kill ring, and instead use `buffer-substring' to
get the header text and insert to `insert' in the buffer.

I would also be a little more careful with the regexps used to match the start
and end tags:

(let ((case-fold-search t)
       beg end level)
   (while (re-search-forward "<h\\([1-5]\\)[^>]*>" nil t)
     (setq beg (match-beginning 0)
	  level (string-to-int (match-string 1))
	  end (re-search-forward (format "</h%d>" level) nil t))a
     (save-excursion
       (goto-char ...);; where the header should be inserted
       (insert (buffer-substring beg end) "\n"))))


-- 
<a href="mailto:&lt;kevin.rodgers&#64;ihs.com&gt;">Kevin Rodgers</a>

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: New to elisp, learning by doing
       [not found]   ` <mailman.2034.1045507046.21513.help-gnu-emacs@gnu.org>
@ 2003-02-17 19:50     ` Kai Großjohann
  0 siblings, 0 replies; 9+ messages in thread
From: Kai Großjohann @ 2003-02-17 19:50 UTC (permalink / raw)


"Ehud Karni" <ehud@unix.mvs.co.il> writes:

> I would do it with strings in a straight forward logic:

That's a nice idea.  Maybe it was a reflex of mine to avoid doing
that.  Have you seen the consing?  ;-)
-- 
A turnip curses Elvis

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: New to elisp, learning by doing
  2003-02-17  9:27   ` Hannu Koivisto
@ 2003-02-18  8:02     ` Kai Großjohann
  0 siblings, 0 replies; 9+ messages in thread
From: Kai Großjohann @ 2003-02-18  8:02 UTC (permalink / raw)


Hannu Koivisto <azure@iki.fi> writes:

> You could do those things if you were a C programmer who only has
> primitive iteration constructs like while and for.

I could also do them things if I didn't grok loop.  ;-)

K(not (programmer :language 'cl))ai
-- 
A turnip curses Elvis

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: New to elisp, learning by doing
  2003-02-17  7:16 ` Kai Großjohann
                     ` (2 preceding siblings ...)
       [not found]   ` <mailman.2034.1045507046.21513.help-gnu-emacs@gnu.org>
@ 2003-02-18 10:26   ` Oliver Scholz
  3 siblings, 0 replies; 9+ messages in thread
From: Oliver Scholz @ 2003-02-18 10:26 UTC (permalink / raw)


kai.grossjohann@uni-duisburg.de (Kai Großjohann) writes:

> Queues are not a standard Lisp datatype, I'm afraid. (Or is there an
> Emacs Lisp package for this?)

FWIW, I have the following lying around, which is stolen&adapted from
Norvig's "Paradigms of Artificial Intelligence Programming".

(defun rtfread-make-queue ()
  "Return a new, empty queue."
  (let ((queue (cons nil nil)))
    (setcar queue queue)))

(defsubst rtfread-enqueue (elt queue)
  "Put ELT to the end of QUEUE."
  (setcar queue
	  (setcdr (car queue)
		  (cons elt nil))))

(defsubst rtfread-dequeue (queue)
  "Pop the first element from the queue.
Returns the removed element."
  (prog1 (pop (cdr queue))
    (when (null (cdr queue))
      (setcar queue queue))))

(defsubst rtfread-queue-contents (queue)
  "Return the contents of QUEUE."
  (cdr queue))

(defsubst rtfread-queue-front (queue)
  "Return the first element of QUEUE."
  (car (rtfread-queue-contents queue)))

(defsubst rtfread-empty-queue-p (queue)
  "Return non-nil if QUEUE is an empty queue."
  (null (rtfread-queue-contents queue)))

(defun rtfread-queue-nconc (queue list)
  "Add the elements of LIST to the end of QUEUE."
  (setcar queue
	  (last (setcdr (car queue) list))))


    Oliver
-- 
30 Pluviôse an 211 de la Révolution
Liberté, Egalité, Fraternité!

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2003-02-18 10:26 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2003-02-16 22:45 New to elisp, learning by doing John Rabkin
2003-02-17  2:03 ` Christopher J. White
2003-02-17  7:16 ` Kai Großjohann
2003-02-17  9:27   ` Hannu Koivisto
2003-02-18  8:02     ` Kai Großjohann
2003-02-17 18:24   ` Ehud Karni
     [not found]   ` <mailman.2034.1045507046.21513.help-gnu-emacs@gnu.org>
2003-02-17 19:50     ` Kai Großjohann
2003-02-18 10:26   ` Oliver Scholz
2003-02-17 18:47 ` Kevin Rodgers

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).