I've said before that AutoHotkey is a great program that every Windows users should have and use. Here's yet another use I found for it to make my (and yours) life easier. Have you ever had two full-screen windows on the same monitor and wanted to switch between them quickly? I encounter that situation regularly. With two or three monitors, I use one in portrait orientation for email and viewing documents, and the others for everything else. To switch between windows, the Task Bar, Alt+Tab and Windows+Tab are great, but when I have 20+ windows open, it can take a fair bit of fiddling and time to switch between email and documents on the same monitor. I wanted a better solution. So I wrote this script (download):
;;;; Window Peeler - Show next window under mouse pointer
#NoEnv ;; Standard prelude
#SingleInstance force
SendMode Input
SetWorkingDir %A_ScriptDir%
;; Pick one of your mouse buttons (XButton1 = Back, XButton2 = Forward, MButton = middle button, LButton = left button, etc.) and use it here:
XButton1::
MouseGetPos,,, WinId
WinSet, Bottom,, ahk_id %WinId%
;MouseGetPos,,, WinId
;WinActivate, ahk_id %WinId%
Return
It moves the window under the cursor to the back when the back button is pressed on your mouse (assuming you have that button). That leaves the next window down on top! The two commented out lines of code activate that window, but I like it without that because it makes the script run quicker. It's a very simple script.
To make it trigger on another combination, for example Control+RightMouseButton, replace XButton1:: with ^RButton:: (^ is for Control).
P.S. Note that mouse software may interfere with the Back and Forward mouse button events. In the Logitech software, I had to set the action for that button to Other: Generic Button.
What do you think? Please leave a comment.
Shedding 'light' on various things, mainly (my) religion, Lisp programming and mathematics.
Saturday 24 November 2012
Saturday 17 November 2012
MathP is not CL Standards Compliant
Bad news! MathP, my very own mathematics notation library for Common Lisp, breaks the ANSI CL standard. The problem is that unread-char cannot be called consecutively without calling something that will read a character (like read-char). From the CL Hyperspec page for unread-char:
I used it to basically peek multiple characters ahead, like peek-char, but for multiple characters. This may be why MathP doesn't work in CLISP. That allows me to have arbitrary operators. For example, I could have the following as distinct operators:
I thought I was being clever, but such a use contravenes the standard pretty clearly. So I'm interested in alternatives. Does anyone know if it's possible to do multiple unread-chars with other stream implementations? Also, can you read lisp from them with standard reading functions?
It is an error to invoke unread-char twice consecutively on the same stream without an intervening call to read-char (or some other input operation which implicitly reads characters) on that stream.
I used it to basically peek multiple characters ahead, like peek-char, but for multiple characters. This may be why MathP doesn't work in CLISP. That allows me to have arbitrary operators. For example, I could have the following as distinct operators:
- * for multiplication
- ** (perhaps for exponentiation)
- .* (perhaps for element-wise multiplication, like in MATLAB)
- *. (dot product?)
- *.* (perhaps for element-wise exponentiation)
- etc.
I thought I was being clever, but such a use contravenes the standard pretty clearly. So I'm interested in alternatives. Does anyone know if it's possible to do multiple unread-chars with other stream implementations? Also, can you read lisp from them with standard reading functions?
Tuesday 13 November 2012
Welcome to Seth Frederick Barton Johansen
Welcome to the world, Seth Frederick Barton Johansen! Seth is the son of Tamara and myself. He was born on the 3rd of November 2012, at 12:21 PM EST at the Wesley Hospital. He weighed 2728g (6 pounds), which is a bit small, but just fine. He also got a bit jaundiced (swallowing blood isn't good for you at that age).
He's now 10 days old, and looking good:
Seth is a biblical name and means "Appointed". Seth was the son of Adam, and is an ancestor to Jesus. He replaced Abel, who was killed by Cain (Genesis 4:25).
He is a little bundle of joy. Good work Tamara (if you're reading this) - you did a great job growing him and giving birth to him - I'm very privileged to be married to you. Thanks Wesley Hospital for supporting Tamara and Seth through labour and the next few days, and to our heavenly father for his blessings, including our first son.
Also, thanks for the well wishes, hugs, flowers, and gifts everyone. They are lovely and appreciated.
P.S. The Wesley Hospital is a great place to have a baby - I can hardly recommend it highly enough. The staff were very friendly and helpful, and went beyond my expectations.
He's now 10 days old, and looking good:
Seth is a biblical name and means "Appointed". Seth was the son of Adam, and is an ancestor to Jesus. He replaced Abel, who was killed by Cain (Genesis 4:25).
He is a little bundle of joy. Good work Tamara (if you're reading this) - you did a great job growing him and giving birth to him - I'm very privileged to be married to you. Thanks Wesley Hospital for supporting Tamara and Seth through labour and the next few days, and to our heavenly father for his blessings, including our first son.
The heart of man plans his way, but the LORD establishes his steps. (Proverbs 16:9)
Also, thanks for the well wishes, hugs, flowers, and gifts everyone. They are lovely and appreciated.
P.S. The Wesley Hospital is a great place to have a baby - I can hardly recommend it highly enough. The staff were very friendly and helpful, and went beyond my expectations.
Saturday 10 November 2012
Some Random Windows Tips
Having used Windows 7 for a while now, I an glad I discovered the Windows Button shortcuts. For me, they save a lot of fiddling with windows. For example, take the Windows+Arrows shortcuts. You may have noticed that it is possible to full-screen (maximise) a window by dragging it to the top of the screen, and to half-screen a window by dragging it to the side of the screen. But if you have multiple monitors, you'll notice that you can't half-screen a window by dragging to the edge of a monitor that abuts another monitor. Do not despair, it's still possible with the Windows+Arrows shortcuts! Here are the basics:
Half-screen a window by dragging it to the left, or pressing Windows+Left. |
Half-screen a window by dragging it to the right, or pressing Windows+Right. |
Moving a window through all monitors and half-screen positions by repeatedly pressing Windows+Right (or Windows+Left). |
Here are some more of my favourite Windows key combinations:
- Windows+D shows the desktop by minimising all windows (like Windows+M);
- Windows+E opens an explorer window;
- Windows+L locks the computer;
- Windows+Tab does a 3D version of Alt-Tabbing.
- Ever had a window that is off-screen and you can't get it back? To get it back, activate the window from the Start Menu, and then press Alt+Space, then M, then press an arrow key (any will do), then move the mouse. I've used this trick since Windows XP to bring back rogue windows.
- To run a program quickly from the keyboard, just press the Windows key, then type in the first few letters of your program's name. If you type enough of the name for it to be the first choice in the Start menu, you can press enter to run it.
Saturday 3 November 2012
MathP and Macros
MathP and macros can be used together a fair bit. I've added a 'math-macro' capability to do custom parsing within MathP input, but you can write macros within MathP (as of version 1.11). I've added direct support for backquote (which has been tested in Corman Common Lisp). Here are some examples of how it all works:
(define-math-macro 'defun (fn (maths)
(multiple-value-bind (args todo) (parse-argument-list (cdr maths));; Skip name
(push (car maths) *global-callables*);; Register the function (for recursion and later)
(multiple-value-bind (body todo) (parse-assignment todo)
(values `((defun ,(car maths) ,args ,@body)) todo)))))
The above shows that the defun math-macro parses the maths (after the defun symbol) as a name, an argument list and an assignment expression. So input maths of '(defun f (x y) x + y z) would be parsed to a list of one form: (defun f (x y) (+ x y)). The remaining maths (the second return value) would be '(z).
The above also shows how parsing is done in MathP. Note that maths is an argument to parsing functions (including the defun parsing function), and that parsing functions return two values. The first is a list of Lisp forms and the second is the maths remaining to be parsed.
But that's really only useful to give existing macros syntax. Let's dive deeper.
#M'a[4]; expands to '(aref a 4)
and
#M`a[4]; expands to `(aref a 4)
#M'(1 2 3+4); expands to '(1 2 3 + 4)
but
#M`(1 2 3+4); expands to `(progn 1 2 (+ 3 4))
#Mdefmacro aif(test then &optional else) `(it=,test if it ,then ,else)
To include a documentation string, just put it and the body into brackets:
#M{defmacro aif(test then &optional else)
{"Anaphoric if defined in MathP"
`(it=,test if it ,then ,else)}}
It's also possible to nest backquotes, but writing a macro with nested backquotes is left as an exercise for the reader.
(defmacro make-more-func (number) `(lambda (n) #M n+,number))
Math-Macro
Macros that use structure in a way that conflicts with the mathematical notation of MathP (that's most macros) can define custom parsing rules. Here's the defun math-macro:(define-math-macro 'defun (fn (maths)
(multiple-value-bind (args todo) (parse-argument-list (cdr maths));; Skip name
(push (car maths) *global-callables*);; Register the function (for recursion and later)
(multiple-value-bind (body todo) (parse-assignment todo)
(values `((defun ,(car maths) ,args ,@body)) todo)))))
The above shows that the defun math-macro parses the maths (after the defun symbol) as a name, an argument list and an assignment expression. So input maths of '(defun f (x y) x + y z) would be parsed to a list of one form: (defun f (x y) (+ x y)). The remaining maths (the second return value) would be '(z).
The above also shows how parsing is done in MathP. Note that maths is an argument to parsing functions (including the defun parsing function), and that parsing functions return two values. The first is a list of Lisp forms and the second is the maths remaining to be parsed.
But that's really only useful to give existing macros syntax. Let's dive deeper.
Backquote
As of MathP v1.1, it is now possible to use backquote (including nested backquotes etc.) in MathP. Backquote is used extensively in macro definitions, but can also be used outside of macros. We'll look at backquote first, to lay the foundation for MathP macros. Backquotes in Common Lisp are described in Section 2.4.6 of the Hyperspec. I've attempted to preserve it's behaviour but there are differences. First, a backquoted MathP expression gets wrapped in a progn if it needs it. One potential point of confusion is that in MathP, quote will quote list content without parsing it, but backquote parses content. Here are some examples of the similarities and differences:#M'a[4]; expands to '(aref a 4)
and
#M`a[4]; expands to `(aref a 4)
#M'(1 2 3+4); expands to '(1 2 3 + 4)
but
#M`(1 2 3+4); expands to `(progn 1 2 (+ 3 4))
Backquote inside MathP
Firstly, a math-macro has been defined for defmacro. It has the same syntax as the defun math-macro. Here's a definition of aif like from On Lisp:#Mdefmacro aif(test then &optional else) `(it=,test if it ,then ,else)
To include a documentation string, just put it and the body into brackets:
#M{defmacro aif(test then &optional else)
{"Anaphoric if defined in MathP"
`(it=,test if it ,then ,else)}}
It's also possible to nest backquotes, but writing a macro with nested backquotes is left as an exercise for the reader.
MathP inside Backquote (Backquote across Lisp and MathP)
I've found that the handling of backquote in Corman Common Lisp doesn't make it possible to consistently backquote a form in Lisp, and unquote something inside it from MathP. If you have a better result in another implementation, please leave a comment. For example (and please excuse the contrived-ness):(defmacro make-more-func (number) `(lambda (n) #M n+,number))
Subscribe to:
Posts (Atom)