Personal tools
You are here: Home



 
Showing blog entries tagged as: unix

More Emacs - a better eshell

Posted by Ricardo Bánffy at Sep 05, 2011 01:35 PM |

Some Emacs users live their entire lives without ever meeting eshell. Eshell is a command-line shell where you can run programs, list directories, copy files and do all kinds of things you would normally need a terminal window for. Eshell even made a cameo appearance in Tron Legacy, as the command-line interface to Encom's computers. Unfortunately, there is something it won't do: it's not easy to start more than one eshell session - when you invoke eshell for the second time, it goes back to the buffer the first eshell opened, normally called "*eshell*". I could invoke the "rename-uniquely" command manually after opening each eshell window (or before attempting to open a new one), but that's annoying (and I ofen forget it).

I keep eshell bound to C-$ (control-$ for the emacs-illiterate ou ^$ for really old-school folks - not that any keyboard I know of emits valid ASCII when someone presses Control-$). I often need more than one shell. "ansi-term" will do the buffer-renaming magic and I can start a number of those, but that's not really what I want - ansi-term runs the shell as a separate process. I use it when I need things I'd need another terminal for, like input and output redirection, but I'd prefer to use eshell when all I need is another shell.

Unfortunate people who don't use Emacs will think I would need to dig up the sources of eshell to add the rename-uniquely invocation and change them. I'll remind those poor folks than your init.el file is, in fact, executed when Emacs starts and, therefore, all I need to do is to change my binding from

(global-set-key (kbd "C-$") 'eshell)

to

(global-set-key (kbd "C-$") '(lambda () 
                               (interactive)
                               (eshell)
                               (rename-uniquely)
                               ))

In case you are wondering, the "interactive" function is invoked to mark this function as a command. If I didn't do it (as I foolishly did earlier this morning, before reading this) I'd be greeted with

Wrong type argument: commandp, (lambda nil (eshell) (rename-uniquely))

That's nice, but not perfect. If you invoke it, you will notice your first eshell buffer is named "*eshell*<2>". That's bad.

It happens because the buffer is uniquely renamed every time it's created, not only when there already is a buffer named "*eshell*". For that, we need a little more code:

(global-set-key (kbd "C-$") '(lambda () 
                               (interactive)
                               (if (member "*eshell*" (mapcar* 'buffer-name 
                                                      (buffer-list)))
                                   (progn (eshell)
                                          (rename-uniquely))
                                   (eshell))))

OK. That was stupid. We test whether there is already a buffer named "*eshell*" and then we try to invoke eshell to create a new one, forgetting that eshell will also find the buffer called "*eshell*" and switch to it rather than creating a new one. We then, dumbly, rename our only eshell buffer.

This thing needs more brains.

Since I don't expect to have more than a handful eshells running (you really shouldn't try to), progressing through numbered buffer names until we find a free one should be a fine approach:

(global-set-key (kbd "C-$") '(lambda () 
                               (interactive)
                               (let ((i 1)
                                     (found-a-name nil))
                                 (while (not found-a-name)
                                   (setq buffname 
                                         (concat "*eshell*<" (int-to-string i) ">"))
                                   (setq found-a-name (not (member buffname 
                                                                   (mapcar* 'buffer-name 
                                                                            (buffer-list)))))
                                   (if found-a-name 
                                       (eshell i)
                                     (setq i (+ i 1))
                                     )))))

Now we start from i = 1 and check if there is already a buffer named "*eshell*<i>". If there is not, create one with that name (passing the number to eshell) and end our search. This is doubly pretty, because the first solution would rename our first eshell as "*eshell*<2>". With this one, the first eshell is "*eshell*<1>", which is elegant. If you manually open an eshell, it'll be called "*eshell*", distinguishing it from our automatically named shells.

Still, as a friend of mine well pointed out, the code is really ugly. It'll also fail if the default name for eshell buffers is changed. In short, it's a mess. I felt compelled to do better:

(global-set-key (kbd "C-$") 
                '(lambda () 
                   (interactive)
                   (let ((i 1))
                   (while (member (concat eshell-buffer-name "<" (int-to-string i) ">")
                                  (mapcar* 'buffer-name (buffer-list)))
                     (setq i (+ 1 i)))
                   (eshell i))))

Much more concise and to-the-point. I like it.

Can you customize Eclipse like that?

A bug. Yes, they hit me too

After publishing this, I noticed the variable eshell-buffer-name is not defined until after you invoke eshell for the first time. If you try to C-$ on a freshly started Emacs session, you'll get a

Symbol's value as variable is void: eshell-buffer-name

message. In order to fix this, the code must check whether eshell-buffer-name is bound and, if it's not, we start the buffer giving it a 1.

(global-set-key (kbd "C-$")
                '(lambda ()
                   (interactive)
                   (let ((i 1))
                     (if (boundp 'eshell-buffer-name)
                         (progn
                           (while (member (concat eshell-buffer-name "<" (int-to-string i) ">")
                                          (mapcar* 'buffer-name (buffer-list)))
                             (setq i (+ 1 i)))
                           (eshell i))
                       (eshell 1))))
)

OK. Now I am satisfied.

Edit: And now, I feel stupid

A friend of mine, very politely, possibly to avoid embarrassing me in public, sent me an e-mail pointing out he didn't quite understood what I was trying to accomplish here. In his message, he pointed out I could just invoke (eshell t). When passed "t" (boolean true in Lisp) as a parameter, eshell does precisely what I wanted it to do. So, the new version in my init.el is even shorter:

(global-set-key (kbd "C-$") '(lambda () (interactive) (eshell t)))

Well... At least I learned something.

Read More…

Emacs perfection - selecting fonts according to screen size

Posted by Ricardo Bánffy at Aug 07, 2011 11:20 AM |

Most of the time, I work at my desk, where my netbook is hooked up to a reasonably sized monitor (the largest its feeble GPU can handle with acceleration). Since screen real-estate in that situation is abundant, I opted to use a larger font (one I made from the x3270 bitmap font, but that's another, much longer story). Unfortunately, when I am not at my desk, the 1024x600 LCD is quite limiting and the default options don't work for me. When I am away from the big screen monitor, screen real-estate is limited and a small font should be selected by default.

I started from the options the Custom menu gave me. Removing comments, it's a very simple snippet:

(custom-set-faces
     '(default ((t (:inherit nil :stipple nil :inverse-video nil :box nil :strike-through nil :overline nil 
       :underline nil :slant normal :weight normal :height 140 :width normal :family "IBM 3270"))))
     '(linum ((t (:inherit default :foreground "#777" :height 110)))))

Translating that to English, I have a font called "IBM 3270" at a 14-point height, with line numbers with 11 points. Very readable.

But that doesn't solve the problem when I am on the road.

The friendly guys at Stack Overflow pointed out one way to do it: x-display-pixel-width and x-display-pixel-height.

With that in hand, I can do:

(if (> (x-display-pixel-width) 1280)
    ; screen is big
    (custom-set-faces
     '(default ((t (:inherit nil :stipple nil :inverse-video nil :box nil :strike-through nil :overline nil 
       :underline nil :slant normal :weight normal :height 140 :width normal :family "IBM 3270"))))
     '(linum ((t (:inherit default :foreground "#777" :height 110)))))
    ; screen is small
    (custom-set-faces
     '(default ((t (:inherit nil :stipple nil :inverse-video nil :box nil :strike-through nil :overline nil 
       :underline nil :slant normal :weight normal :height 110 :width normal :family "IBM 3270"))))
     '(linum ((t (:inherit default :foreground "#777" :height 80)))))
)

and I can be happy.

But can I?

When I start Emacs without X (as in from a remote terminal), these functions issue an ugly warning telling me that X is not available and that I should --debug-init and fix the problem. That's safely ignorable (as these adjustments are being done when everything non-cosmetic is already in place, at least in my init.el), but, still, annoying.

There is a variable, window-system, that can help - it holds "x" if we are under the X windowing system and nil if we are using a character terminal. With it, I can do:

(if (and (eq 'x window-system) (> (x-display-pixel-width) 1280))
    ; screen is big
    (custom-set-faces
     '(default ((t (:inherit nil :stipple nil :inverse-video nil :box nil :strike-through nil :overline nil 
       :underline nil :slant normal :weight normal :height 140 :width normal :family "IBM 3270"))))
     '(linum ((t (:inherit default :foreground "#777" :height 110)))))
    ; screen is small
    (custom-set-faces
     '(default ((t (:inherit nil :stipple nil :inverse-video nil :box nil :strike-through nil :overline nil 
       :underline nil :slant normal :weight normal :height 110 :width normal :family "IBM 3270"))))
     '(linum ((t (:inherit default :foreground "#777" :height 80)))))
)

short-circuiting the x-display-pixel-width and allowing Emacs starts cleanly from a remote terminal session. Since window-system also can tell you if you are on a Mac (or NeXT, if you are into retrocomputing) or under Windows (you can't argue taste), you can take appropriate actions according to your environment.

I am happy for today.

Read More…

Por que você não deve deixar de ir à LinuxCon só por causa do keynote do Sandy Gupta

Os amigos

Muitos amigos meus estão dizendo que não vão à LinuxCon Brazil por conta de um keynote por um representante da Microsoft. Isso me preocupa muito e me preocupou a ponto de eu me decidir a escrever este post

O mentiroso

A Microsoft é uma entidade engraçada. É extremamente consistente e previsível. Joga baixo, sempre que pode. Seus funcionários acreditam, de coração, que está tudo bem e que é normal fazer essas coisas. Se me convidarem pra jogar bola, eu não vou. Devem dar caneladas, cotoveladas e tudo o mais que puderem, desde que acreditem que vão ficar impunes.

Sandeep Gupta veio da SCO. Foi ele o cara (eu pensei em usar "mané", mas ele sabia muito bem o que estava fazendo) que anunciou (PDF) que havia código do Unix no Linux. Eu escrevi sobre isso há muito tempo - desde então se provou que o Linux não tem código Unix nele e que a SCO não tinha nenhum direito sobre o código que ela dizia ser dela que ela dizia que foi parar (e não foi) dentro do Linux. Lá ele chegou a ser presidente da SCO Operations, seja lá o que fosse que ela operasse.

Muita gente suspeita que a SCO foi apenas um laranja para a Microsoft. A Microsoft tem uma série de coincidências interessantes de executivos que destruíram competidores e que, depois disso, acabaram trabalhando em cargos prestigiosos da empresa. Um que eu me lembro fácil é Rick Beluzzo, que fez com que a HP praticamente abandonasse o desenvolvimento do HP-UX e priorizar servidores Windows, porque, nas palavras dele "NT é o futuro" (em tempo - a divisão de servidores da HP que mais dava lucro era a dos HP-UX, na última vez que eu olhei). Depois da HP ele foi a Silicon Graphics (mais ou menos na época em que a Microsoft comprou a Softimage e estabeleceu o NT como alternativa viável para animação) e que acabou licenciando a preço de banana a tecnologia de aceleração de 3D deles para a Nvidia (que permitiu PCs com performance de 3D similar às SGIs e que enterrou de vez o negócio deles). Depois disso ele foi parar na MSN e deve ter ganho seus vários milhões com isso tudo. A história de Gupta é um paralelo notável e demonstra que, se não a SCO, pelo menos ele esteve a serviço da Microsoft desde o início.

Você contrataria um executivo como ele?

Nem eu.

Mas esse não é o ponto. O homem é um pulha e a Microsoft não é uma empresa ética. Isso não é segredo e nem é a primeira vez que eu digo isso.

O evangelista

James Plamondon era um evangelista da Microsoft. Em uma apresentação, ele explicou como se faz para esvaziar um evento de um competidor - a Microsoft simplesmente aparece no evento. Plamondon, nessa entrevista, se vangloria de ter acabado com duas conferências de desenvolvedores de Mac tornando-as multi-plataforma e impondo tracks com palestras que não interessam a ninguém. Desenvolvedores de software para Mac não querem ir a uma conferência para assistir palestras sobre como escrever software para Windows. Ao impor sua presença, ele espanta conferencistas e, a longo prazo, estrangula a conferência, que morre, aparentemente, de causas naturais. A primeira foi a Mac App Developers Conference, onde ele era membro do board da associação por trás. A segunda foi a Technology and Issues Conference. As duas tiveram uma vida longa antes da Microsoft decidir acabar com elas.

Está tudo aqui. Essa parte que eu mencionei está na página 27, mas o PDF tem 66 páginas de pura maldade (o método que ele usou para entrar na grade de uma conferência é particularmente maligno). Esse pessoal não é só ultra-competitivo. Eles não tem caráter nenhum.

O vilão

Não tenha dúvida de que a Microsoft pagou, direta e indiretamente, para estar na LinuxCon. Mas nós ganhamos com isso. O evento fica melhor no geral, tem mais dinheiro, as entradas podem ser mais baratas e o lanche pode ser melhor. O espaço pode ser mais bem-cuidado, as palestras podem ter mais pessoas. E o preço disso é que temos a oportunidade de ir lá e detonar com o cara no keynote dele. Gente! É o cara da SCO! Melhor que isso só se fosse Bill Gates! Ele vai ser um alvo fácil falando por uma hora. Você pode estar no auditório e, quando ele subir ao palco, sair como forma de protesto (cuidado - ele vai usar a carta da "intolerância" e do "fanatismo" para nos demonizar). Melhor é ficar e crivá-lo com as perguntas mais pontudas e cortantes que puderem imaginar. Se você tiver uma credencial de imprensa, use-a para fazer perguntas na entrevista coletiva. O cara é mau e merece. Simboliza e protagoniza tudo o que existe de mais errado em nosso mercado. Eu lamento profundamente não poder ir pessoalmente dessa vez, mas minha oportunidade de trollá-lo vai chegar.

O que não podemos fazer

Essa parte é muito importante.

Evidentemente, não podemos usar de violência. Eu imagino que também não seja permitido entrar com tortas no auditório. Mais importante do que tudo isso é não deixarmos que a Microsoft esvazie o evento. Se você não aprova e não tem estômago pra ficar ouvindo, vá para o corredor durante o keynote fazer alguma coisa. É uma LinuxCon, afinal. Vá escrever algum código que ajude os outros. Encontre alguém e vá resolver algum problema seu. Deixe que ele fale sozinho sobre a interoperabilidade que a empresa dele não quer. Distribua folhetos, imprima a página 27, traduza, publique em seu blog. Faça algo. Eles vivem da nossa inação.

Mas, mais do que tudo isso, não deixe de ir. O evento e a comunidade a que ele serve não precisam de Guptas e Plamondons.

Precisam de você.

Read More…

Monkey business

Posted by Ricardo Bánffy at Sep 05, 2009 01:25 PM |
Filed under: piada unix linux

Ah... The stuff you find in your DNS logs...

Sep  5 07:21:03 heinlein named[1825]: client 200.171.10.117#1481: query (cache) 
'www.itau.com.br.planetofapes/A/IN' denied

Would anyone with über-sysadmin superpowers care to explain what that means?

Read More…