Jekyll2023-12-20T10:26:18+00:00/feed.xmlYing Hong Tham’s websiteToki yo tomareWriting Vim Slime for Julia2023-12-20T00:00:00+00:002023-12-20T00:00:00+00:00/2023/12/20/vimslime-from-scratch<p>Lately I’ve been writing Julia for some projects,
and since it has an interactive mode,
I like to write code in a file, then copy it out to the REPL to execute.
It gets a bit tiresome to have to highlight, copy, switch terminals,
paste, then switch back. Of course someone else has encountered
this same problem before, and wrote some scripts to help with it.
I first learned of this possibility with Emacs SLIME mode,
and later I found this vim plugin <a href="https://github.com/jpalardy/vim-slime/tree/main">vim-slime</a>,
though it didn’t have a ftplugin for Julia.
I decided to try to roll my own version,
to get some more experience working with terminals and buffers,
inspired by my little adventure with Build-Your-Own-Editor.</p>
<p>Initially I attempted to just <code class="language-plaintext highlighter-rouge">echo</code> out the yanked text
and pipe it to the Julia REPL process, but for some reason
it didn’t work, it seemed like it was piping the text to its
parent terminal process…
Then I tried tmux, which is used in vim-slime,
but I couldn’t figure out how to send text to other panes…
Then I followed <a href="https://technotales.wordpress.com/2007/10/03/like-slime-for-vim/">original version of vim-slime</a>
which used <code class="language-plaintext highlighter-rouge">screen</code>, but ultimately it could not handle many lines…
Eventually I found <code class="language-plaintext highlighter-rouge">tmux</code>’s functionalities for working with buffers,
and got it to work!</p>
<p><code class="language-plaintext highlighter-rouge">~/.config/nvim/ftplugin/julia.vim</code>:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>function Send_Clipboard_to_Pane()
if !exists("g:julia_pane")
call Set_Julia_Pane_Prompt()
end
" create a buffer in tmux called x-clip and copy contents from clipboard
call system("tmux set-buffer -b x-clip \"$(xclip -o -selection clipboard)\"")
call system("tmux paste-buffer -b x-clip -t " . g:julia_pane)
call system("tmux send-keys -t " . g:julia_pane . " 'Enter'")
endfunction
function Set_Julia_Pane_Prompt()
if !exists("g:julia_pane")
" suggested default value; see pane number with $ tmux list-pane
let g:julia_pane = "%1"
end
let g:julia_pane = input("tmux pane: ", g:julia_pane)
endfunction
" yank current function into clipboard (register "+)
function YankJuliaFunction()
" save current cursor position
let save_cursor = getcurpos()
let save_winview = winsaveview()
" search for the latest function above cursor, then delete search record
call search("function", "b")
call histdel("search", -1)
" use % to move to end; default julia.vim already handles with matchit
execute "norm 0V%"
redraw
sleep 50ms
execute "norm \"+y"
" return cursor to start position
call setpos('.', save_cursor)
call winrestview(save_winview)
endfunction
" yank current block into clipboard (register "+)
" blocks are delineated with markers #++#
function YankJuliaBlock()
" save current cursor position
let save_cursor = getcurpos()
let save_winview = winsaveview()
if search("#++#", "bW") == 0
" failed to find marker, go to top of file
execute "norm gg"
end
call histdel("search", -1)
execute "norm 0Vj"
if search("#++#", "W") == 0
execute "norm G"
end
redraw
sleep 50ms
call histdel("search", -1)
execute "norm \"+y"
" return cursor to start position
call setpos('.', save_cursor)
call winrestview(save_winview)
endfunction
nmap <F6> :call YankJuliaFunction()<CR>
nmap <F7> :call YankJuliaBlock()<CR>
nmap <F9> :call Send_Clipboard_to_Pane()<CR>
</code></pre></div></div>
<p>I also have the following key binding in general in <code class="language-plaintext highlighter-rouge">~/.config/nvim/init.vim</code>:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>"send to clipboard selection
vmap <F8> "+y
nmap <F8> :let @+=@"<CR>
</code></pre></div></div>Lately I’ve been writing Julia for some projects, and since it has an interactive mode, I like to write code in a file, then copy it out to the REPL to execute. It gets a bit tiresome to have to highlight, copy, switch terminals, paste, then switch back. Of course someone else has encountered this same problem before, and wrote some scripts to help with it. I first learned of this possibility with Emacs SLIME mode, and later I found this vim plugin vim-slime, though it didn’t have a ftplugin for Julia. I decided to try to roll my own version, to get some more experience working with terminals and buffers, inspired by my little adventure with Build-Your-Own-Editor.Build Your Own Text Editor2023-12-10T00:00:00+00:002023-12-10T00:00:00+00:00/2023/12/10/build-editor<p>Several weeks ago, I came across the
<a href="https://github.com/codecrafters-io/build-your-own-x">Build Your Own X</a>
GitHub repo, which has many step-by-step tutorials on
how to do things from scratch (“from scratch” being a relative term).
I wanted to try something pretty low-level,
and decided to go with
<a href="https://viewsourcecode.org/snaptoken/kilo/index.html">C: Build Your Own Text Editor</a>.</p>
<p>The tutorial is very well paced and clearly explained,
and it feels very natural to follow.
It builds features incrementally, starting with very basic versions,
then modifying them to handle more complicated versions,
for example, handling user input begins with only single characters,
then later modified to also handle escaped sequences.</p>
<p>It has been quite a while, probably about 8 years,
since I used C in any substantial manner,
and it brought up some nostalgia for my early coding days.
It was refreshing and surprisingly fun to have to once again deal with
low-level bit-manipulation, e.g. bit flags and pointer arithmetic,
after so many years of mostly coding only in high-level languages.</p>
<p>One takeaway I have is: a text editor is just loads an array of strings
into memory and provides an interface to transform those strings.
I mean, obviously that is what it is, and one could say that virtually
for any program, e.g. a browser is just a fancy way of displaying html.
But somehow I felt like a veil had been lifted.
I think the fact that the editor uses the terminal as a sketchpad
contributed to this feeling - I’ve always felt that the terminal
as this mysterious box, complete and inert, somehow untouchable,
even though I use it everyday for nvim.</p>
<p>Doing this project has inspired me to want to try other Build Your Own X
projects. I would very much like to do one of the Physics Engine
tutorials, as I really like visualizations
(e.g. <a href="https://www.youtube.com/@NilsBerglund">Nils Berglund</a>’s channel).</p>Several weeks ago, I came across the Build Your Own X GitHub repo, which has many step-by-step tutorials on how to do things from scratch (“from scratch” being a relative term). I wanted to try something pretty low-level, and decided to go with C: Build Your Own Text Editor.Workshop on “Transitioning from Academia”2023-12-03T00:00:00+00:002023-12-03T00:00:00+00:00/2023/12/03/data-science-workshop<p>Last week I attended a short 3-day workshop on
“Transitioning from Academia: Developing a Career with Python”
with an emphasis on data science,
which was organized by <a href="https://pier-hamburg.de">PIER</a>
and faciltated by <a href="https://alexbritz.de/">Alex Britz</a>.</p>
<p>The scope of the workshop was quite broad,
jumping from strategies for the job search like networking
and preparing a good landing page, to a whirlwind tour of
some technical aspects of doing the job of a data analyst/scientist,
like standard packages (pandas, numpy, seaborn etc.)
and newer tools like ChatGPT and Github Copilot,
as well as methods to share and present results,
e.g. <a href="https://www.data-to-viz.com/">data visualizations</a>
and <a href="https://streamlit.io/">Streamlit</a>.</p>
<p>One of my key takeaways is that in a non-academic setting,
ultimately people only want to know two things:
what problem we are solving, and what the results are.
This was not news to me, but I think the workshop really hammered it home,
particularly when Alex blitzed through a project in 30 minutes
with the help of ChatGPT.
Actually this is not too dissimilar to communication in academia,
especially when speaking to someone in a different field of research,
though some people, perhaps out of politeness, may follow up with questions
about methods employed or challenges faced.
One may even argue that a well-written academic paper should
have a similar goal-oriented emphasis, in particular in the introduction,
where the main theorem is clearly stated.
Regardless, I should practice being to the point when describing
the goals and outcome of my work.</p>
<p>Reflecting on my experience doing data analysis at my previous job at
Albert Einstein College of Medicine
attempting to predict the cell-to-cell contact based on the
gene expression in each cell,
I was constantly experimenting with the data,
and despite producing many Python scripts and using many different models,
I never felt that I had arrived at a conclusion,
always uneasy about the outcome of my experiments.
While certainly my inexperience in data analysis contributed to
this feeling of unease,
I also think that the environment, being that of a biology lab
focused on fundamental research,
suggested that all of the results I obtained should only be taken
as suggestions for further research with real experiments,
rather than anything definitive or worth writing about.
(I should note that I was mainly employed as a web developer.)</p>
<p>Another thing I appreciate about the workshop was being in the
company of academics who are leaving academia,
many of whom also do not speak German very fluently.
They shared many of the same concerns I had,
e.g. being “overqualified” with a PhD,
competing with younger data science majors,
falling short of a 100% fit with the job description etc.</p>
<p>Finally, I enjoyed collaborating on a data analysis project.
We found a data set on <a href="https://www.kaggle.com/datasets/vinven7/comprehensive-database-of-minerals/">Kaggle</a>
concerning the properties of minerals, which interested us both.
We wrote our own code, but it was still really helpful to be able
to bounce ideas off one another,
especially since neither of us knew much about minerals.
Here is my <a href="https://github.com/YingHongTham/DataAnalysis/tree/main/mineral_properties">notebook</a>.</p>Last week I attended a short 3-day workshop on “Transitioning from Academia: Developing a Career with Python” with an emphasis on data science, which was organized by PIER and faciltated by Alex Britz.Getting copy/paste to work2021-04-18T05:06:15+00:002021-04-18T05:06:15+00:00/2021/04/18/copypaste<p>Copy/paste between Firefox and terminal wasn’t working
(I run Archlinux with i3wm).
Here’s my workaround.</p>
<p>Install <code class="language-plaintext highlighter-rouge">xclip</code>, which manages 3 clipboards:</p>
<ul>
<li>primary; for things being highlighted. Contents of the primary clipboard are
ephemeral, and get overwritten when something else is highlighted.
Moreover, it is asynchronous, so if the program in which the text is copied
from is terminated, the selection disappears.</li>
<li>secondary: mysterious</li>
<li>clipboard: from which regular <code class="language-plaintext highlighter-rouge">ctrl+v</code> is pasted from.</li>
</ul>
<p>So we bind <code class="language-plaintext highlighter-rouge"><F8></code> to copy contents of primary to clipboard.
First copy the default configuration for <code class="language-plaintext highlighter-rouge">xbindkeys</code> to <code class="language-plaintext highlighter-rouge">~/.xbindkeysrc</code>:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ xbindkeys -d > ~/.xbindkeysrc
</code></pre></div></div>
<p>Then add the following:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>"xclip -o -selection primary | xclip -i -selection clipboard"
F8
</code></pre></div></div>
<p>Load the file with</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ xbindkeys
</code></pre></div></div>
<p>or add it to <code class="language-plaintext highlighter-rouge">~.xinitrc</code>.</p>
<p>After highlighting something, say in visual mode in Vim,
<code class="language-plaintext highlighter-rouge"><F8></code> acts as a sort of “copy” button.
(I would use <code class="language-plaintext highlighter-rouge">ctrl+shift+c</code>, but Firefox already has that shortcut taken.)</p>
<p>Also, pasting into terminal doesn’t work great,
so we assign <code class="language-plaintext highlighter-rouge"><F9></code> to pasting,
by adding the following to <code class="language-plaintext highlighter-rouge">~/.Xresources</code>:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>*VT100*translations: #override \n\
<Key>F9: insert-selection(PRIMARY,CLIPBOARD)
</code></pre></div></div>Copy/paste between Firefox and terminal wasn’t working (I run Archlinux with i3wm). Here’s my workaround.Low Battery Notifications2021-04-18T03:04:55+00:002021-04-18T03:04:55+00:00/2021/04/18/low-battery-notifications<p>When my laptop’s battery hits 5%,
it makes a small beep sound.
However, sometimes I would miss it if I happen to be away,
or would plug the cable into a power outlet but forget that
the other end is not plugged into my laptop…
So I wrote a simple systemd service that beeps every 10 seconds
after the battery drops below 10%.</p>
<p>The logic is very simple: invoke a script every 10 seconds;
the script checks if battery is not being charged and
is less than 10%, and beep if so.</p>
<p>Systemd config files are kept in /etc/systemd/system.
Here I have a timer file that tells the computer
to call the service every OnUnitActiveSec=10s
(AccuracySec=1s means the time is checked every 1 second)</p>
<p>/etc/systemd/system/battery-beep.timer:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[Unit]
Description=Battery beep when low
[Timer]
OnUnitActiveSec=10s
OnBootSec=10s
AccuracySec=1s
[Install]
WantedBy=timers.target
</code></pre></div></div>
<p>By default, the service file with the same name is invoked.</p>
<p>/etc/systemd/system/battery-beep.service:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[Unit]
Description=Beep regularly if battery is low
[Service]
Type=oneshot
ExecStart=/bin/bash /path/to/battery-beep.sh
</code></pre></div></div>
<p>The script can be put anywhere, I put them somewhere in my
home directory.
/path/to/battery-beep.sh:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#!/bin/bash
BATINFO=`acpi -i`
MYPOWER=$(cat /sys/class/power_supply/BAT0/energy_now)
MYPOWERFULL=$(cat /sys/class/power_supply/BAT0/energy_full)
if [[ `echo $BATINFO | grep Discharging` && $((MYPOWER * 100 / MYPOWERFULL)) -le 10 ]] ; then beep; fi
</code></pre></div></div>
<p>Of course, you should have <code class="language-plaintext highlighter-rouge">beep</code> installed.
Oddly, beeps start to kick in around 9%,
I think because MYPOWERFULL is not actually the amount of charge
when battery is 100%; indeed, my fully charged laptop shows 80%
and not 100%…</p>
<p>Load the service as follows:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ systemctl daemon-reload #takes in changes in config files
$ systemctl start battery-beep.timer
$ systemctl enable battery-beep.timer #load at boot
</code></pre></div></div>When my laptop’s battery hits 5%, it makes a small beep sound. However, sometimes I would miss it if I happen to be away, or would plug the cable into a power outlet but forget that the other end is not plugged into my laptop… So I wrote a simple systemd service that beeps every 10 seconds after the battery drops below 10%.