20090802

ghc 6.10.4 solves the previous problem with sendtorepl

Upgrading to ghc 6.10.4 does solve the problem that I previously wrote about with 6.10.3:
http://renick-bell.blogspot.com/2009/05/upgrade-to-ghc-6103-broke-my-vim-script.html
Because of that, the workaround that I described previously is no longer needed:
http://renick-bell.blogspot.com/2009/05/workaround-for-sendtorepl-and-ghci.html
Thanks to the tireless developers!

20090531

Workaround for sendtorepl and ghci

Judah, the author of haskeline, says:
"This was probably caused by a bug which has been fixed in the latest
release of Haskeline (0.6.1.6).

That fix should ship with ghc-6.10.4"
In the meantime, he gave me this solution, which works here:
cabal update && cabal install ghci-haskeline
Then, you should not interact with your 6.10.3 ghci; rather, you should interact with the executable ghci-haskeline, which is probably here:
~/.cabal/bin/ghci-haskeline
So now, when I start my screen session that I plan to interact with, I use this line:
screen -S haskellSession -t haskellSession ~/.cabal/bin/ghci-haskeline
Ghc-6.10.4 should not require this simple workaround.

20090530

Upgrade to ghc 6.10.3 broke my vim script

If you by chance tried my vim script, it no longer works in ghci 6.10.3 for multiple lines. I'm not sure why, yet. Some amount of the beginning of the string is cut, and the final bit of the string, :}\n is also cut. There was a change from editline to haskeline. Could that be the reason?

20090506

Send text from vim to any REPL

Like I said back in April, I'd been looking for a convenient way to interact with any REPL from vim. Nothing had been satisfactory until I found Mr. Martinez's vicle.vim, which is in turn based on Jonathan Palardy's slime.vim. Thanks to both of them! I really learned a lot. Vicle was a great starting point. However, I wanted a little different behavior from it. It needed modification to play well with GHCi and literate Haskell.

Now I have a decent initial version. I've tried single lines with GHCi, Python, and the shell. I've done blocks in GHCi. All seem to work fine. I guess any REPL works for single lines: Octave, R, maybe an ftp session, etc. Multiple lines with a REPL other than GHCi will require modification of the script. Please try it and let me know if it has problems or if you have any suggestions on how it could be improved. it requires GNU Screen. The biggest problem I know of with it is the 4096 byte limitation mentioned by Mr. Martinez. It would be nice to find a way around that.

Like vicle.vim and slime.vim, you will need GNU Screen. I start it with something like this:
screen -S haskellSession -t haskellSession ghci
Map the commands at the bottom to convenient keys in your .vimrc. I use Enter for :SendtoreplSend and in visual mode also Enter for :SendtoreplSendBlock. For blocks, it's also convenient to do something like map F10 to the command sequence "vip".

Download sendtorepl.vim: http://www.srl.im.dendai.ac.jp/renick/sendtorepl.vim

It's time to get busy using this.

20090504

For editline, don't bind jj to vi-command-mode!

I've hesitated posting my version of vicle because I was having what I thought was a weird bug. Somehow, only things with "j" in them were not working. It seemed like "j" and the next character were always omitted from the input to ghci. Finally it occurred to me to try sending the output to bash rather than ghci, and suddenly there was no problem. So the problem was in ghci. Then I remembered that I had done some things in .ghci and .editrc. The latter is where I found I had a line "bind jj vim-command-mode". That turned out to be really bad choice.

And here's where I got that from:
bind -v
bind \\t rl_complete
bind ^L ed-clear-screen
bind jj vi-command-mode <<<--- DON'T DO THIS!!! Esc is good enough! Remap the Windows key or CapsLock to Esc if necessary.

http://www.nabble.com/example-editrc-td21152004.html

I'm grateful to Brian for that message, because it showed me how to get vi bindings in ghci. However, that jj line cost me at least a couple of hours! That's a lesson to myself not to blindly copy and paste without understanding what I'm copying and pasting.

*slaps self upside the head*


Now I can finish cleaning up my version of vicle and post it.

This .bashrc should be tested a bit.

OK. I've really got to get to work. There's lots more changes. It's going to take some time using this to find out what parts are not needed, and where there's missing stuff. If you have any suggestions, I'd love to hear them.

# to be added to .bashrc
#-----------------------------------------------------------------------------
# file management and navigation

alias g="pushd"
alias b="popd"
alias gh="pushd ~"
alias gr="pushd /"
alias gd="pushd ~/documents/"
alias gm="pushd /media/disk1part3/renick/music/"
alias l='ls -a --group-directories-first | less -rn'
alias ls='ls -CF'
alias ll='ls -lahGp --color=always --group-directories-first | less -rn'
alias lst='ls -lahGpt --color=always --group-directories-first | less -rn'
alias lsd="ls -d */"
alias duh='du -h --max-depth=1 | less'
alias dus='du | sort -nr | less'
alias ..='pushd ..'
alias ...='pushd .. ; pushd ..'

# do ". acd_func.sh"
# acd_func 1.0.5, 10-nov-2004
# petar marinov, http:/geocities.com/h2428, this is public domain
# with the aliases below, type "dl" to see a directory list of recently accessed directories
# then "cd -" and the number from the menu

cd_func ()
{
local x2 the_new_dir adir index
local -i cnt

if [[ $1 == "--" ]]; then
dirs -v
return 0
fi

the_new_dir=$1
[[ -z $1 ]] && the_new_dir=$HOME

if [[ ${the_new_dir:0:1} == '-' ]]; then
#
# Extract dir N from dirs
index=${the_new_dir:1}
[[ -z $index ]] && index=1
adir=$(dirs +$index)
[[ -z $adir ]] && return 1
the_new_dir=$adir
fi

#
# '~' has to be substituted by ${HOME}
[[ ${the_new_dir:0:1} == '~' ]] && the_new_dir="${HOME}${the_new_dir:1}"

#
# Now change to the new dir and add to the top of the stack
pushd "${the_new_dir}" > /dev/null
[[ $? -ne 0 ]] && return 1
the_new_dir=$(pwd)

#
# Trim down everything beyond 11th entry
popd -n +11 2>/dev/null 1>/dev/null

#
# Remove any other occurence of this dir, skipping the top of the stack
for ((cnt=1; cnt <= 10; cnt++)); do
x2=$(dirs +${cnt} 2>/dev/null)
[[ $? -ne 0 ]] && return 0
[[ ${x2:0:1} == '~' ]] && x2="${HOME}${x2:1}"
if [[ "${x2}" == "${the_new_dir}" ]]; then
popd -n +$cnt 2>/dev/null 1>/dev/null
cnt=cnt-1
fi
done

return 0
}

alias cd=cd_func

if [[ $BASH_VERSION > "2.05a" ]]; then
# ctrl+w shows the menu
bind -x "\"\C-w\":cd_func -- ;"
fi

alias dl='cd --'

# system for making quick bookmarks
alias +1='echo ~+ > ~/.path1'
alias +2='echo ~+ > ~/.path2'
alias +3='echo ~+ > ~/.path3'
alias +4='echo ~+ > ~/.path4'
alias +5='echo ~+ > ~/.path5'
alias +6='echo ~+ > ~/.path6'
alias +7='echo ~+ > ~/.path7'
alias +8='echo ~+ > ~/.path8'
alias +9='echo ~+ > ~/.path9'
alias +0='echo ~+ > ~/.path0'
# list the bookmarks
alias bl='for i in '~/.path*'; do echo -e "\E[37;44m""$i";cat $i; done; tput sgr0'
# go to the numbered bookmark
j () { pushd "$(cat ~/.path$1)"; }

alias yp='echo ~+ > ~/.yankedpath'
alias pp='cat ~/.yankedpath'
alias G='pushd `pp`'

alias ,d='mkdir'
# move something to the previously yanked path
,m () { mv $1 `pp`; }
# copy something to the previously yanked path
,c () { cp $1 `pp`; }

# extract any archive
xx () {
if [ -f $1 ] ; then
case $1 in
*.tar.bz2) tar xvjf $1 ;;
*.tar.gz) tar xvzf $1 ;;
*.bz2) bunzip2 $1 ;;
*.rar) unrar x $1 ;;
*.gz) gunzip $1 ;;
*.tar) tar xvf $1 ;;
*.tbz2) tar xvjf $1 ;;
*.tgz) tar xvzf $1 ;;
*.zip) unzip $1 ;;
*.Z) uncompress $1 ;;
*.7z) 7z x $1 ;;
*) echo "'$1' cannot be extracted via >extract<" ;;
esac
else
echo "'$1' is not a valid file"
fi
}

# tar a directory
alias td='tar -czvf'
# zip a directory
alias zd='zip -r'

More tweaking of my .bashrc when I should be getting other work done.

I think it's a kind of procrastination, but I've tweaked several things, like using pushd instead of cd and a way to list the bookmarks. Maybe this is useful to someone besides myself.

#-----------------------------------------------------------------------------
# file management and navigation

alias g="pushd"
alias b="popd"
alias gr="pushd /"
alias gm="pushd /media/disk1part3/renick/music/"
alias l='ls -a --group-directories-first | less -rn'
alias ls='ls -CF'
alias ll='ls -lahGp --color=always --group-directories-first | less -rn'
alias llt='ls -lahGpt --color=always --group-directories-first | less -rn'
alias lsd="ls -d */"
alias duh='du -h --max-depth=1 | less'
alias dus='du | sort -nr | less'
alias ..='pushd ..'
alias ...='pushd .. ; pushd ..'

# system for making quick bookmarks
alias +1='echo ~+ > ~/.path1'
alias +2='echo ~+ > ~/.path2'
alias +3='echo ~+ > ~/.path3'
alias +4='echo ~+ > ~/.path4'
alias +5='echo ~+ > ~/.path5'
alias +6='echo ~+ > ~/.path6'
alias +7='echo ~+ > ~/.path7'
alias +8='echo ~+ > ~/.path8'
alias +9='echo ~+ > ~/.path9'
alias +0='echo ~+ > ~/.path0'
# list the bookmarks
alias lb='for i in '~/.path*'; do echo -e "\E[37;44m""$i";cat $i; done; tput sgr0'
# go to the numbered bookmark
j () { pushd "$(cat ~/.path$1)"; }

alias yp='echo ~+ > ~/.yankedpath'
alias pp='cat ~/.yankedpath'

alias G='pushd `pp`'

# extract any archive
xx () {
if [ -f $1 ] ; then
case $1 in
*.tar.bz2) tar xvjf $1 ;;
*.tar.gz) tar xvzf $1 ;;
*.bz2) bunzip2 $1 ;;
*.rar) unrar x $1 ;;
*.gz) gunzip $1 ;;
*.tar) tar xvf $1 ;;
*.tbz2) tar xvjf $1 ;;
*.tgz) tar xvzf $1 ;;
*.zip) unzip $1 ;;
*.Z) uncompress $1 ;;
*.7z) 7z x $1 ;;
*) echo "'$1' cannot be extracted via >extract<" ;;
esac
else
echo "'$1' is not a valid file"
fi
}

20090502

Trying to get by without my favorite file manager: Worker.

With a recent update to my Debian Sid setup, my file manager, Worker, has become unbearably slow. I couldn't use it anymore.

http://www.boomerangsworld.de/worker/

I have used mc in the past, but what kills me about it is that I can't configure the keyboard shortcuts. Half of the commands overlap with my window manager keyboard shortcuts. I suppose I could reconfigure my window manager, and I may yet go that route.

I'm still hoping that Ralf will fix Worker, and there's the way mentioned above. However, in the meantime, I thought it might be a good exercise to see if I could make working from the shell as comfortable as using Worker. I've started on some things in my .bashrc. Here they are; I'd be appreciative if anyone can tell me of similar tricks and other conveniences for making working with files and directories from the shell faster.

#-----------------------------------------------------------------------------
# file management and navigation

alias g="pushd"
alias b="popd"
alias gr="cd /"
alias gm="cd /media/disk1part3/renick/music/"
alias l='ls -a --group-directories-first | less -rn'
alias ls='ls -CF'
alias ll='ls -lahGp --color=always --group-directories-first | less -rn'
alias llt='ls -lahGpt --color=always --group-directories-first | less -rn'
alias lsd="ls -d */"
alias duh='du -h --max-depth=1 | less'
alias dus='du | sort -nr | less'
alias ..='cd ..'
alias ...='cd .. ; cd ..'

# system for making quick bookmarks
alias +1='echo ~+ > ~/.path1'
alias +2='echo ~+ > ~/.path2'
alias +3='echo ~+ > ~/.path3'
alias +4='echo ~+ > ~/.path4'
alias +5='echo ~+ > ~/.path5'
alias +6='echo ~+ > ~/.path6'
alias +7='echo ~+ > ~/.path7'
alias +8='echo ~+ > ~/.path8'
alias +9='echo ~+ > ~/.path9'
alias +0='echo ~+ > ~/.path0'
# go to the numbered bookmark
gg () { cd "$(cat ~/.path$1)"; }

alias yp='echo ~+ > ~/.yankedpath'
alias pp='cat ~/.yankedpath'

alias G='cd `pp`'

# extract any archive
xx () {
if [ -f $1 ] ; then
case $1 in
*.tar.bz2) tar xvjf $1 ;;
*.tar.gz) tar xvzf $1 ;;
*.bz2) bunzip2 $1 ;;
*.rar) unrar x $1 ;;
*.gz) gunzip $1 ;;
*.tar) tar xvf $1 ;;
*.tbz2) tar xvjf $1 ;;
*.tgz) tar xvzf $1 ;;
*.zip) unzip $1 ;;
*.Z) uncompress $1 ;;
*.7z) 7z x $1 ;;
*) echo "'$1' cannot be extracted via >extract<" ;;
esac
else
echo "'$1' is not a valid file"
fi
}

20090420

When using map in a vim script...

I was struggling with editing this script when calling the map function. What I was missing was that in the expression following the list (l:block in the example below), it's necessary to surround your function call in single quotes, like this:
  • call map(l:block,'Vicle_strip_birds(v:val)')
That's because even though it's a function call, it's a string as far as the map function is concerned. That's kind of weird for me.

*Shrug*

At least the script works now.

20090417

interacting with a REPL from vim

This is a really good starting point for using vim with a REPL (Wikipedia says calling it an "interpreter" is wrong). Mr. Martinez has done a nice job.

http://www.vim.org/scripts/script.php?script_id=2551

I've wanted something this simple for a while. Being used to scvim for SuperCollider, I wanted the same thing when using other interpreted languages, like Octave, Scheme, and now Haskell. I tried other similar scripts, but they were too complex. This is almost right. I'm modifying it to suit me, and then I'll post it.

20090323

Using Glade and Gtk2Hs with Haskell on Debian Sid

I wanted to try this tutorial:

http://haskell.org/gtk2hs/docs/tutorial/glade/

For me, there were many difficulties. Actually, it seems that the problems were user error on my part, discovered after trying to repeat the process on a second computer. You need to install the dependencies:

apt-get install gtk2hs-doc libghc6-cairo-dev libghc6-gconf-dev libghc6-glade-dev libghc6-glib-dev libghc6-gnomevfs-dev libghc6-gstreamer-dev libghc6-gtk-dev libghc6-gtkglext-dev libghc6-soegtk-dev libghc6-sourceview-dev libghc6-svgcairo-dev

All of this works, except for:

E: Couldn't find package libghc6-sourceview-dev

Then I had to adjust my .hs file to match the contents of the XML file generated by Glade. For instance, I changed line 9 to read:

window <- xmlGetWidget xml castToWindow "HelloGTK2hs"

CORRECTION: This was my mistake. I typed "HelloGTK2hs" in the "name" field rather than the "window title" field. Be careful!

A note to myself: it might be wise to try a process a second time on another computer before writing a blog post!