; a simple line editor for reading lisp expressions. ; colors strings and comments. nested parens get different colors. ; ; needs to do its own raw keyboard/screen management since we need to decide ; how to color each key right as it is printed. ; lots of logic devoted to handling backspace correctly. ; keyboard screen abort continuation -> string (function read-expression [ (default-space:space-address <- new space:literal 60:literal) (k:keyboard-address <- next-input) (screen:terminal-address <- next-input) (abort:continuation <- next-input) (history:buffer-address <- next-input) ; buffer of strings (history-length:integer <- get history:buffer-address/deref length:offset) (current-history-index:integer <- copy history-length:integer) (result:buffer-address <- init-buffer 10:literal) ; string to maybe add to (open-parens:integer <- copy 0:literal) ; for balancing parens and tracking nesting depth ; we can change color when backspacing over parens or comments or strings, ; but we need to know that they aren't escaped (escapes:buffer-address <- init-buffer 5:literal) ; to not return after just a comment (not-empty?:boolean <- copy nil:literal) { begin ; repeatedly read keys from the keyboard ; test: 34 (done?:boolean <- process-key default-space:space-address k:keyboard-address screen:terminal-address) (loop-unless done?:boolean) } ; trim trailing newline in result (easier history management below) { begin (l:character <- last result:buffer-address) (trailing-newline?:boolean <- equal l:character ((#\newline literal))) (break-unless trailing-newline?:boolean) (len:integer-address <- get-address result:buffer-address/deref length:offset) (len:integer-address/deref <- subtract len:integer-address/deref 1:literal) } ; test: 3 => size of s is 2 (s:string-address <- to-array result:buffer-address) (reply s:string-address) ]) (function process-key [ ; return t to signal end of expression (default-space:space-address <- new space:literal 60:literal) (0:space-address/names:read-expression <- next-input) (k:keyboard-address <- next-input) (screen:terminal-address <- next-input) (c:character <- wait-for-key k:keyboard-address silent:literal/terminal) (len:integer-address <- get-address result:buffer-address/space:1/deref length:offset) (maybe-cancel-this-expression c:character abort:continuation/space:1) ; check for ctrl-d and exit { begin (eof?:boolean <- equal c:character ((ctrl-d literal))) (break-unless eof?:boolean) ; return empty expression (s:string-address-address <- get-address result:buffer-address/space:1/deref data:offset) (s:string-address-address/deref <- copy nil:literal) (reply t:literal) } ; check for backspace ; test: 34 ; todo: backspace past newline { begin (backspace?:boolean <- equal c:character ((#\backspace literal))) (break-unless backspace?:boolean) (print-character screen:terminal-address c:character/backspace) { begin ; delete last character if any (zero?:boolean <- lesser-or-equal len:integer-address/deref 0:literal) (break-if zero?:boolean) (len:integer-address/deref <- subtract len:integer-address/deref 1:literal) ; switch colors ; test: "a"bc" ; test: "a\"bc" { begin (backspaced-over-close-quote?:boolean <- backspaced-over-unescaped? result:buffer-address/space:1 ((#\" literal)) escapes:buffer-address/space:1) ; " (break-unless backspaced-over-close-quote?:boolean) (slurp-string result:buffer-address/space:1 escapes:buffer-address/space:1 abort:continuation/space:1 k:keyboard-address screen:terminal-address) (reply nil:literal) } ; test: (+ 1 (2) ; test: (+ 1 #\(2) { begin (backspaced-over-open-paren?:boolean <- backspaced-over-unescaped? result:buffer-address/space:1 ((#\( literal)) escapes:buffer-address/space:1) (break-unless backspaced-over-open-paren?:boolean) (open-parens:integer/space:1 <- subtract open-parens:integer/space:1 1:literal) (reply nil:literal) } ; test: (+ 1 2) 3) ; test: (+ 1 2#\) 3) { begin (backspaced-over-close-paren?:boolean <- backspaced-over-unescaped? result:buffer-address/space:1 ((#\) literal)) escapes:buffer-address/space:1) (break-unless backspaced-over-close-paren?:boolean) (open-parens:integer/space:1 <- add open-parens:integer/space:1 1:literal) (reply nil:literal) } } (reply nil:literal) } ; up arrow; switch to previous item in history { begin (up-arrow?:boolean <- equal c:character ((up literal))) (break-unless up-arrow?:boolean) ; if history exists ; test: up without history has no effect { begin (empty-history?:boolean <- lesser-or-equal history-length:integer/space:1 0:literal) (break-unless empty-history?:boolean) (reply nil:literal) } ; if pointer not already at start of history ; test: 34 up past history has no effect { begin (at-history-start?:boolean <- lesser-or-equal current-history-index:integer/space:1 0:literal) (break-unless at-history-start?:boolean) (reply nil:literal) } ; then update history index, copy into current buffer ; test: 34 up restores previous command ; test todo: 342334 up doesn't mess up typing on current line ; test todo: 345 commands don't modify history ; test todo: multi-line expressions ; identify the history item (current-history-index:integer/space:1 <- subtract current-history-index:integer/space:1 1:literal) (switch-to-history 0:space-address screen:terminal-address) ; is trimmed in the history expression, so wait for the human to ; hit again or backspace to make edits (reply nil:literal) } ; down arrow; switch to next item in history { begin (down-arrow?:boolea
<html>
	<head>
		<title>dwm - dynamic window manager</title>
		<meta name="author" content="Anselm R. Garbe">
		<meta name="generator" content="ed">
		<meta name="copyright" content="(C)opyright 2006 by Anselm R. Garbe">
		<style type="text/css">
			body {
				color: #000000;
				font-family: sans-serif;
				margin: 20px 20px 20px 20px;
			}
		</style>
	</head>
	<body>
		<center>
			<img src="dwm.png"/><br />
			<h3>dynamic window manager</h3>
		</center>
		<h3>Description</h3>
		<p>
		dwm is a dynamic window manager for X11.
		</p>
		<h3>Philosophy</h3>
		<p>
		As founder and main developer of wmii I came to the conclusion that
		wmii is too clunky for my needs. I don't need so many funky features
		and all this hype about remote control through a 9P service, I only
		want to manage my windows in a simple, but dynamic way. wmii never got
		finished because I listened to users, who proposed arbitrary ideas I
		considered useful. This resulted in an extreme <a href="http://www.jwz.org/doc/cadt.html">CADT</a>
		development model, which was a mistake. Thus the philosophy of
		dwm is simply <i>to fit my needs</i> (maybe yours as well). That's it.
		</p>
		<h3>Differences to wmii</h3	
		<p>
		In contrast to wmii, dwm is only a window manager, and nothing else.
		Hence, it is much smaller, faster and simpler.
		</p>
		<ul>
			<li>
			dwm has no 9P support, no menu, no editable tagbars,
			no shell-based configuration and remote control and comes without
			any additional tools like printing the selection or warping the
			mouse.
			</li>
			<li>
			dwm is only a single binary, it's source code is intended to never
			exceed 2000 SLOC.
			</li>
			<li>
			dwm is customized through editing its source code, that makes it
			extremely fast and secure - it does not process any input data which
			hasn't been known at compile time, except window title names.
			</li>
			<li>
			dwm is based on tagging and dynamic window management (however simpler
			than wmii or larswm).
			</li>
			<li>
			dwm don't distinguishes between layers, there is no floating or
			managed layer. Wether the clients of currently selected tag are
			managed or not, you can re-arrange all clients on the fly. Popup-
			and fixed-size windows are treated unmanaged. 
			</li>
			<li>
			dwm uses 1-pixel borders to provide the maximum of screen real
			estate to clients. Small titlebars are only drawn in front of unfocused
			clients.
			</li>
			<li>
			dwm reads from <b>stdin</b> to print arbitrary status text (like the
			date, load, battery charge). That's much simpler than larsremote,
			wmiir and what not...
			</li>
			<li>
			garbeam <b>does not</b> want any feedback to dwm. If you ask for support,
			feature requests, or if you report bugs, they will be <b>ignored</b>
			with a high chance. dwm is only intended to fit garbeams needs.
			However you are free to download and distribute/relicense it, with the
			conditions of the <a href="http://wmii.de/cgi-bin/hgwebdir.cgi/dwm?f=f10eb1139362;file=LICENSE;style=raw">MIT/X Consortium license</a>.
			</li>
		</ul>
		<h3>Screenshot</h3>
		<p>
		<a href="http://wmii.de/shots/dwm-20060714.png">Click here for a screenshot</a> (20060714)
		</p>
		<h3>Development</h3>
		<p>
		dwm is actively developed in parallel to wmii. You can <a href="http://wmii.de/cgi-bin/hgwebdir.cgi/dwm">browse</a> its source code repository or get a copy using <a href="http://www.selenic.com/mercurial/">Mercurial</a> with following command:
		</p>
		<p>
		<code>hg clone http://wmii.de/cgi-bin/hgwebdir.cgi/dwm</code>
		</p>
		<h3>Download</h3>
		<p>There is no release yet.</p>
		<h3>Miscellaneous</