[Prev][Next][Index][Thread]

Re: Question on implementing a Deuce command



"Chris Double" <chris@double.co.nz> wrote in message
wkk7yfwlzv.fsf@double.co.nz">news:wkk7yfwlzv.fsf@double.co.nz...
> Doing some playing around with Deuce, the Dylan Editor, I thought I'd
> try implementing the equivalent of some Emacs Lisp packages to see
> what programming with Deuce is like compared to Emacs.

By way of apology or perhaps just defensiveness, I have to point out
that I didn't design Deuce to have a super-convenient extension language
like gnuemacs.  It requires a bit more programming.  This deficiency is
mainly due to the schedule constraints we had -- we needed an editor
that did the job, more than we needed a Dylan reinvention of gnuemacs.

> Starting simple, I used morse.el, and attempted a morse.dylan. There
> being little in the way of Deuce documentation I thought I'd post my
> attempt here to get some feedback as to whether I'm doing it the right
> way - or if there are other ways of doing it.
>
> Here's my 'morse-region' code:
>

Here's my annotated version:

define command morse-region(frame)
    "Convert the selected text to morse code."
  let bp1 = copy-bp(point());
  let bp2 = mark();
  when(bp2)
    do-morse-region(frame, bp1, bp2);
  end when;
end command morse-region;

define method do-morse-region(frame,
                              bp1 :: <basic-bp>,
                              bp2 :: <basic-bp>)
 => ()
  let window = frame.frame-window;
  let buffer = frame.frame-buffer;
  // *** DELETE UPCASED CODE -- 'MAKE-INTERVAL' DOES THE RIGHT THING
  LET REVERSE? = BP-LESS?(BP1, BP2);
  let interval = make-interval(bp1, bp2, IN-ORDER?: REVERSE?);
  check-read-only(interval);
  clear-mark!();
  queue-region-redisplay(window, bp1, bp2, centering: #f);

  local method morse-line(line :: <line>, si :: <integer>, ei :: <integer>,
last?)
    // *** DELETE UPCASED CODE -- 'INSERT!' AND 'KILL!' DO THE RIGHT THING
    LET LINE = NOTE-LINE-CHANGED(LINE);
    let contents = line-contents(line);
    // *** YOU COULD SAFELY USE 'AS-LOWERCASE!' SINCE YOU'RE ABOUT TO
    // *** KILL THAT INTERVAL ANYWAY
    let morse = convert-to-morse(AS-LOWERCASE(CONTENTS), start: si, end:
ei);
    let start-bp = make-bp(line, si);
    let end-bp = make-bp(line, ei);

    // *** IT WOULD BE MORE EFFICIENT TO USE 'LINE-CONTENTS-SETTER'
    // *** IN THE CASE WHERE YOU ARE MUNGING THE WHOLE LINE
    // *** (TOO BAD 'DELETE-WITHIN-LINE' ISN'T EXPORTED...)
    insert!(kill!(make-interval(start-bp, end-bp)), morse);
  end method morse-line;

  with-change-recording(buffer, <replace-change-record>, interval: interval)
    do-lines(morse-line, interval);
  end with-change-recording;
end method do-morse-region;

> ------------------8<-------------------------
>
> Note that 'convert-to-morse' takes a string and converts it to morse
> code in much the same way as morse.el does it. It returns the
> converted string. I won't post my attempt at convert-to-morse and
> convert-from-morse just yet. An exercise for the reader!
>
> I couldn't work out how to do the conversion character by character
> within the Deuce buffer itself, so I went for the function that
> returns a converted string and did it line by line. How would I do it
> character by character 'in-place'?

I think you made the correct choice -- it's much more efficient to snip
out a whole interval and then replace it in one go than it is to do it
one character at a time.

> Is the 'note-line-changed' needed? What exactly does that do? Inform
> clients that the line has changed so it can be redisplayed?

No to the first question, and your third question is the correct answer
to the second one.

> The 'with-change-recording' macro...Does that do the do/undo handling
> for me? I notice I can undo the morse-region.

Yes, it handles undo/redo for you.  The "undo class" tells the undo/redo
facility what sort of changes you are making so that the most efficient
representation for change can be used.

> I added this code to 'standalone-deuce' and it worked ok. Just curious
> if it's the right approach. Deuce is fairly large and there is a lot
> in there.

Pretty good first stab, if you ask me.

Note to self:
 - Export 'delete-within-line' from deuce-internals
 - Export 'insert-into-line' from deuce-internals








Follow-Ups: References: