2017-04-13
Keyboard Shortcut to Focus Last Tab in Safari
In Safari, contrary to every other browser out there, ⌘9 switches to the 9th tab and not the last one. This can easiy be solved with an Alfred workflow.
The workflow triggers only in Safari on ⌘9 (or any keyboard shortcut you configure). It runs an AppleScript to figure out the tab count and goes to the last tab:
on alfred_script(q)
tell application "Safari"
tell front window
set current tab to tab (count tabs)
end tell
end tell
end alfred_script
You can download the finished workflow here:
Safari - Focus Last Tab.alfredworkflow (1.0.0)
macOS
2011-05-20
All Erlang Modules in the Code Path
Here’s a little thing of beauty to get all Erlang modules in your code path, should you ever need it:
[list_to_atom(filename:basename(F, ".beam"))
|| P <- code:get_path(), F <- filelib:wildcard("*.beam", P)].
2011-01-17
Erlang Alignment in Emacs
Just realized that the default align
function in Emacs is quite capable. To indent, for example, a list of tuples with data, add the following alignment rule to your .emacs
-file:
(add-hook 'align-load-hook
(lambda ()
(add-to-list 'align-rules-list
'(erlang-align
(regexp . ",\\(\\s-+\\)")
(repeat . t)
(modes quote (erlang-mode))))))
This will add a new alignment rule that aligns comma separated regions with whitespace. It will align all occurrences over all lines in the region, and only be enabled in the Erlang mode.
The alignment will transform this:
[{a, 19, "test", <<0,0>>},
{abc, 2, "a", <<12,19,28,11>>}].
Into this:
[{a, 19, "test", <<0,0>>},
{abc, 2, "a", <<12,19,28,11>>}].
I set it to Ctrl+E in my .emacs
-file:
(global-set-key (read-kbd-macro "C-E") 'align)
I can also recommend the align-repeat
macro from Align Commands on Emacs Wiki. I set it to Ctrl+Shift+E.
Erlang
programming
Emacs
2010-10-13
Synchronized, Reliable Message Passing in Erlang
To do proper, synchronized message passing you need three things: monitoring, timeout and a unique tag in the messages.
Basic Case
The basic case is sending a blocking request to a server process.
request(Pid, Request) ->
Pid ! {request, Request},
receive
{reply, Response} ->
Response
end.
This gives us a nice way to send a request to a server and wait for a reply, but it can fail for several reasons:
- The server process is not alive
- The server process crashes before it sends an answer
- The server process takes to long time to respond
- We receive an old reply to another request
Monitoring
To check if the process is alive or if it crashes during the request is done by monitoring the process. It is also possible to use links, but that requires trapping exits and should not be done dynamically (a process should either trap exits or not when it is started, and keep that behavior for its lifetime).
A monitor is set up by calling erlang:monitor(process, Pid)
. This will instantly set up a monitor for the process and as soon as the monitored process dies Erlang will send this message to the caller: {'DOWN', MonitorRef, Type, Object, Info}
where
MonitorRef
is the return value from the call erlang:monitor/2
Type
is the atom process
Object
is the monitored pid
Info
is the exit reason for the process or noproc
(if the process didn’t exist) or noconnection
(for node connections).
The fine thing with erlang:monitor/2
is that it will always send a message to the caller. So if the process is already dead when setting up the monitor, it will still send a down message with the Info
set to noproc
. This allows us to write quite generic code:
request(Pid, Request) ->
MRef = erlang:monitor(process, Pid),
Pid ! {request, Request},
receive
{reply, Response} ->
Response;
{'DOWN', MRef, process, Pid, Reason} ->
{error, Reason}
end.
Timeouts
Even if the server stays alive, it might take too long to respond. Either it is too busy, or there is a bug making it take to long to process the request or it froze. This can be fixed with a receive timeout:
request(Pid, Request, Timeout) ->
MRef = erlang:monitor(process, Pid),
Pid ! {request, Request},
receive
{reply, Response} ->
Response;
{'DOWN', MRef, process, Pid, Reason} ->
{error, Reason}
after Timeout ->
{error, timeout}
end.
Unique Messages
The last feature is added to avoid mixing up responses to requests made from the same process. The timeout we added in the last part can actually result in the server replying after the client timed out and stopped caring about the response. This will result in the response ending up in the mail box of the client process, which could be accidentally picked up the next time we wait for a response. To avoid this we create a unique reference using the built in function make_ref/0
:
request(Pid, Request, Timeout) ->
MRef = erlang:monitor(process, Pid),
Ref = make_ref(),
Pid ! {request, Ref, Request},
receive
{reply, Ref, Response} ->
Response;
{'DOWN', MRef, process, Pid, Reason} ->
{error, Reason}
after Timeout ->
{error, timeout}
end.
This assumes the server responds with the same reference that the request contained. Just remember to flush the mailbox for any old responses lying around, otherwise that will be a memory leak!
Erlang
programming
2010-09-30
Compact Choices in Erlang
To avoid the verbose case statements in Erlang, I sometimes use this function:
ifc(true, True, _) -> True;
ifc(false, _, False) -> False;
So instead of writing this:
case proplists:is_defined(empty, Options) of
true -> [];
false -> [some_default]
end
One can write this:
ifc(proplists:is_defined(empty, Options), [], [some_default])
The idea was to mimic the simplicity of C’s (and other languages) ?
operator.
Erlang
programming