Jan 05, 2014
I like tabbar-mode
and the buffer cycling options it provides. I can cycle between buffers in a single group (especially useful when cycling scope is limited to tabs
) and between different groups. This makes it much easier to manage many open buffers within different contexts (such as projects).
(require 'tabbar)
(tabbar-mode t)
(setq tabbar-cycle-scope 'tabs)
(global-set-key (kbd "s-{") 'tabbar-backward-group)
(global-set-key (kbd "s-}") 'tabbar-forward-group)
(global-set-key (kbd "s-[") 'tabbar-backward)
(global-set-key (kbd "s-]") 'tabbar-forward)
Grouping
The grouping defaults are reasonable (by major mode name), but could be better. We'll use the default tabbar-buffer-groups-function
from tabbar.el
as a basis. This section contains the entire function budy.
(defun my-tabbar-buffer-groups ()
"Return the list of group names the current buffer belongs to.
Return a list of one element based on major mode."
(list
*Process* group
The default grouping separates "process" buffers into their own group. This is a problem with flycheck
, for example. When flycheck does its thing the buffer briefly becomes a "process" buffer, causing tabbar to yank it between groups. This makes for a very jittery tab bar. Let's fix that by removing the "Process" group altogether:
(setq my-group-by-project nil)
(cond
;; ((or (get-buffer-process (current-buffer))
;; ;; Check if the major mode derives from `comint-mode' or
;; ;; `compilation-mode'.
;; (tabbar-buffer-mode-derived-p
;; major-mode '(comint-mode compilation-mode)))
;; "Process"
;; )
OK, better. Now our flychecked files stay grouped by major mode.
((member (buffer-name)
'("*scratch*" "*Messages*"))
"Common"
)
((eq major-mode 'dired-mode)
"Dired"
)
((memq major-mode
'(help-mode apropos-mode Info-mode Man-mode))
"Help"
)
((memq major-mode
'(rmail-mode
rmail-edit-mode vm-summary-mode vm-mode mail-mode
mh-letter-mode mh-show-mode mh-folder-mode
gnus-summary-mode message-mode gnus-group-mode
gnus-article-mode score-mode gnus-browse-killed-mode))
"Mail"
)
Grouping by project
While working on multiple projects the tab bar quicly becomes unwieldy. I prefer to group mine by "project name:mode name" instead. I use projectile
for getting the name of the project.
Also, for small projects I like to be able to group by project name alone. For this I defined a simple toggle variable my-group-by-project
.
(t
;; Return `mode-name' if not blank, `major-mode' otherwise.
(let ((group
(if (and (stringp mode-name)
;; Take care of preserving the match-data because this
;; function is called when updating the header line.
(save-match-data (string-match "[^ ]" mode-name)))
mode-name
(symbol-name major-mode))))
(if (projectile-project-p)
(if my-group-by-project
(projectile-project-name)
(format "%s:%s" (projectile-project-name) group))
group))
))))
Performance tuning
tabbar-mode
calls tabbar-buffer-groups-function
A LOT -- for each open buffer for every single keystroke. Since projectile-project-name
is not a super fast function this will slow Emacs down. Assuming we never want buffers to change groups, we could quasi-memoize this function and cache group names per every project. We can do this with a pseudo-closure.
(defun my-cached (func)
"Turn a function into a cache dict."
(lexical-let ((table (make-hash-table :test 'equal))
(f func))
(lambda (key)
(let ((value (gethash key table)))
(if value
value
(puthash key (funcall f) table))))))
;; evaluate again to clear cache
(setq cached-ppn (my-cached 'my-tabbar-buffer-groups))
(defun my-tabbar-groups-by-project ()
(funcall cached-ppn (buffer-name)))
(setq tabbar-buffer-groups-function 'my-tabbar-groups-by-project)
Now, tabbar will be fetching a cached group name for existing buffers. To wipe the cache we recreate the closure by reevaluating.
Finally, wire the toggle (we must clear the cache for regrouping to take effect):
(defun my-toggle-group-by-project ()
(interactive)
(setq my-group-by-project (not my-group-by-project))
(message "Grouping by project alone: %s"
(if my-group-by-project "enabled" "disabled"))
(setq cached-ppn (my-cached 'my-tabbar-buffer-groups)))
Oct 01, 2013
Life has changed a little since the last report.
- A maxed out MacBook Air has replaced the Pro and I love it. The screen hinge is weak, the screen is reflective — those are annoying, yes. But overall, it weighs nothing, runs a VM effortlessly and I can work unplugged the whole day.
- sshfs and 10.8 are no longer friends. Sublime cannot reliably detect file changes anymore, so instead the guest OS now mounts a shared folder.
- Having to use
mercurial
sucks and may deserve a separate post.
May 30, 2013
Over the past couple of years I have had the fortune to pick up some
great habits from great people. It is time to share an updated setup.
These are the things my work-life currently depends on.
Python
Life environment: OSX, iMac, MacBook Pro, and recently back to iPhone.
Dev environment: VirtualBox. I still like free, and VBox works
just fine.
Dev OS: Ubuntu Server. No more esoteric nonsense like Arch. The
skinnier Server Edition is preferred as I need very little graphics
capability from my Linux. Cannot stand Linux GUIs.
Now, how it all works together:
- Linux runs the code and manages packages. All the dev stuff stays
there. Linux runs in headless mode.
- OSX runs the editor (Sublime Text), terminal (iTerm), browsers,
etc. and keeps my senses happy with beautiful fonts.
sshfs: the sanest way I know to share files between host and
guest OSes. I keep a virtual directory mounted locally on OSX and
point the editor there.
X11: always ready when I do need to bring up a GUI tool over a
tunnel (I always ssh -X into my virtual machine), which are:
- git gui, gitk: if they are not part of your git-fu already, you
are missing out
- tig: very useful for a quick history browse
- IPython+Notebook: I often run my code as I'm testing it, and
IPython is the way to interact with the interpreter. As the
experiment grows or whenever working with data plots, firing up
Notebook is worth the hassle.
- nose+mock: I finally learned to stop worrying and love the tests.
Yes, tests are always worth having.
- Sublime Text: this probably deserves a separate post. In short,
breaking away from the IDE land has been a happy change.
- pianobar
Nov 03, 2010
Entirely free. Requires XCode.
Download and install Soundflower.
Open Audio MIDI Setup.
Create Aggregate Device (Audio -> Open aggregate device editor),
constisting of:
- Built-in output (or whatever output you need)
- Soundflower
Set default output to Soundflower.
Start audio. At this point you should hear nothing.
Open AU Lab (/Developer/Applications/Audio/AU Lab.app).
Add 1 stereo input track, set Audio Device to "Aggregate device".
Click "Done".
Now you should hear sound and see level meters move.
In either Audio 1 or Output 1 strip, click Effects drop-down and
select Apple Graphic EQ, or whatever else you want!
Voila.
Mar 05, 2010
After installing Atlassian Connector in Eclipse and everything just goes
to shit: all installed plugins disappear from preferences. The problem,
as it turns out, lies in installing Eclipse as root (sudo pacman -S) and
later installing plugins while Eclipse is running as non-root.
So, the right thing to do is either:
- run Eclipse as root when installing packages; or
- chown /usr/share/eclipse to the appropriate user.
http://subclipse.tigris.org/ds/viewMessage.do?dsForumId=1046&dsMessageId=2391942
Feb 09, 2010
After updating to GWT 2.0.1 (official) and moving our project to a
arch/vbox, I had a small adventure trying to get DevMode window to come
up: it just wouldn't. The window just came up blank and nothing else
happened.
It turns out you are running awesome, Java may not play nice. You
need this:
http://tools.suckless.org/wmname
And remember to export GDK_NATIVE_WINDOWS=true to make all your
Eclipse buttons work correctly.
Thanks to selckin on ##gwt for wmname suggestion.
Feb 02, 2010
You can sync two Things instances between two Macs easily by copying
~/Library/Application Support/Cultured Code/. But this works if only
the donor instance has diverging changes. What if both instances have
unique new items?
You can sync Things iPhone to multiple Things.app instances. My problem
was that items move from a Mac to the iPhone, but not from the iPhone to
the other Mac. And this is the solution for merging Things from one Mac
to the other:
- Bring up Things on Mac A, sync iPhone, shut down Things.
- Bring up Things on Mac B, sync iPhone, shut down Things. Now iPhone
has items from both Macs, but Mac B doesn't.
- On Mac B, remove/backup
~/Library/Application Support/Cultured Code/Things/Database.xml
- Pair and sync iPhone to Mac B again.
Jan 26, 2010
After two weeks of research and experimentation, finally arrived at the
settings that stop Eclipse from making you want to gouge your eyes out.
This goes into ~/.Xdefaults:
Xft.dpi: 76 #84 for 27" iMac
Xft.antialias: true
Xft.hinting: true
Xft.hintstyle: hintslight
Xft.rgba: rgb
And this is what's installed (in that order):
drwxr-xr-x 2 root root 4096 Jan 15 11:26 pkgconfig-0.23-1
drwxr-xr-x 2 root root 4096 Jan 15 12:00 freetype2-ubuntu-2.3.11-2
drwxr-xr-x 2 root root 4096 Jan 15 12:02 fontconfig-ubuntu-2.6.0-8
drwxr-xr-x 2 root root 4096 Jan 15 12:29 libxft-ubuntu-2.1.14-2
drwxr-xr-x 2 root root 4096 Jan 15 13:05 cairo-ubuntu-1.8.8-1
drwxr-xr-x 2 root root 4096 Jan 18 10:13 ttf-inconsolata-20090215-1
drwxr-xr-x 2 root root 4096 Jan 18 10:15 ttf-bitstream-vera-1.10-6
drwxr-xr-x 2 root root 4096 Jan 25 22:06 ttf-dejavu-2.30-1
And this is why we like to use Macs.
By the way, the .Xdefaults bit above also helps with X11 on the Mac
(yay for wireshark).
Jan 21, 2010
This was unexpected enough to warrant a mention: the PER hangs when it
is sent any of the upgrade sysex'es (OS, DSP, Voice). It shows the
"loading" message, but the countdown doesn't start.
The setup:
- PER v2.0, upgrading to 2.1
- Edirol PCR-M1 as a MIDI interface
- 10.6 and 10.5 Macs, latest drivers for the respective OS'es
- SysEx Librarian, PolyEvolver500 editor
So it appears the PCR-M1 is doing something of which Dave Smith does not
approve. I would be curious to find out what.
For the meantime, UM-880 worked just fine.
Jan 19, 2010
This is surprisingly elusive, so here it is. After creating a debug/run
target with Run/Debug as... -> Python run, add this variable in the
Environment tab:
PYTHONPATH $PWD
If you're debugging Django, add another:
DJANGO_SETTINGS_MODULE settings
You will also want to add --noreload to your runserver argument.