How to read Vim's source code?

11 views
Skip to first unread message

Ian

unread,
Jul 13, 2025, 2:30:00 AM7/13/25
to vim...@vim.org
Hello,
I'm having trouble understanding some parts of Vim's source code. The
problem I'm facing is somewhat specific but I think the questions I
have can be generalized to the one in the title.

I'll start giving some context on my problem and end with the general
questions; feel free to take all the time you want to respond, I
understand you are all really busy:
I am trying to implement support for variable-width fonts in gVim; I
know it is an unattractive feature for lots of people, and I'm not
expecting anyone to jump to coding it, I am fine with me putting in
the effort (until I give up, at least). Also, my general questions
bellow still apply without this feature in mind. I am mostly
interested in the "generalized questions"; so for discussion on the
specific feature I can open a new post if you want.

Note: If I can't make myself understood, tell me and I'll try to
explain it differently; my english is far from perfect.

So far I:
- Started by reading main, vim_main2 and main_loop, to see how it
works generally.
- Investigated some call trees (with ctags & grep).
- Somewhat understood gui initialization: gui_start,
gui_mch_init, etc.
- The gui loop: done with g_main_context_iteration while
waiting for a char in ui_inchar and friends.
- gui_outstr_nowrap prints / draws the string (tested
variable width fonts by disabling the "hack" to make it
fixed width when 'font=' is set; and it somewhat worked).
- ...
- Went through all win_line, commenting and folding it by sections.
(I thought I had undestood the relevant parts of it but now I think
I haven't.)
- ...

TL;DR: I have have exhausted my ideas on how to figure this out.

My concrete problems (to give context):
1. I can't figure out how to get the `font=` highlight attribute (or
it's equivalent 'ae_u.gui.font' entry in attrentry_T) inside
win_line. There's wlv.char_attr (that should be available after the
"Decide which of the highlight attributes to use" block). But I
suspect it must be of a different kind than in other places of the
source (like the aep in gui_outstr_nowrap) because when I read it I
get corrupted values for the font pointer.
2. I have discovered and want to use the n_extra, c_extra, mechanism
to do some replacement of some text with spaces. I also can't get it
right, I suspect it's behaviour is dependent on where you put the
code in between the win_line function. But I can't see any obvious
place where I should put it. (Right now I've tried to put it at the
end of the else of the "Get the next character to put on the screen"
if statement.)

Back to the title and the general questions:
I feel like I must be doing something wrong and there is a more
straight forward way to _really_ read a function and understand its
implications without the need of knowing all the other source code (as
an example, it was difficult for me to see that gui_mch_init is
"hidden" inside termcapinit and set_termname). Right now it's as if
any function can change any variable in the global state (and there is
a lot of global state). It's also as if arguments of the function
don't say anything about what the function "recieves" nor what it
"gives back" to the rest of the code.
So:

1. How do you manage to do it?

I've read somewhere that some just specialize in a part of the code
and know it well, so:

2. How do you deal with fixing a bug that spans multiple subsystems?

Also, I'm not just talking about maintaining the project, I'm
fascinated with the idea of someone, not familiar with the code, and
adding a new somewhat complex feature they need (e.g. concealing is
pretty complex), without having to backtrack all Vim's history and
read everything to understand a small part.

3. So how did you tackle reading the source for the first time?

4. And after being involved for some time, do you have any
suggestions you would have liked to have known in the
beginning?

Thanks to anyone reading this and to anyone that answers, I hope it's
not too boring.

---

Finally, this text is already getting pretty long but I'll try to
explain how I'm thinking of implementing the feature, and justify
myself for thinking it shouldn't be too complicated.

I think the really important part of my email are the general
questions, so you can safely ignore this if you are not really
interested.

If someone ends up interested in this I can open a new discussion if I
figure out how to do some more work on it.

- Add an "attribute" 'vwfont' to the highlight attribute 'gui=' that
enables the feature with the 'font=' set. (For the prototype I was
just trying to enable this always that 'font=' is set.)
- Obviously this feature only makes sense in the gui version, like
the 'font=' attribute.
- Detect the attribute in win_line for a block of text and:
- Activate a feature-specific code that:
- Calculates the width of the resulting occupied string (with
pango, etc.)
- Caches the width values for ascii letters at least (maybe
store it "inside" the font, have the font be represented by
GuiFont and this cache.)
- If it doesn't fit in the screen, do something to make wrap
work (keep in mind that more characters fit than cells in a
row).
- The string itself is stored in the buffer/window, there's no
problem of it not being in ScreenLines.
- Store some kind of global structure array (per row) for
identifying this "variable width block". (Could contain an
x_offsets array calculated later).
- Replace the text (in ScreenLines) with the minimum number of
spaces it would need to fit the width calculated earlier. Using
the n_char, c_char mechanism. Also adding a marker with a
special highlight attribute to signal the drawer later.
- Later, when outputting the string, maybe in gui_outstr_nowrap,
activate some code when the marker is detected, refer to the
allocated array with structure information and draw it. Saving in
the process the x_offsets (pixel horizontal position offset) so
that we can later draw just one character (and the cursor).
- For drawing the cursor detect we are on a "special block" and
completely give control to some feature specific code.

Other ideas I can explain if someone is interested:
- Also taking into account font height. Text bigger than a "fixed
size" row.
- How it would combine monospace and variable width text in a line.
- There's lots of things that lose usefulness for variable width
fonts (like visual block selection), but that doesn't mean the
feature is bad.
- The curor moving up or down (j & k).
- cursorcol, etc.

Thanks, again, for reading this.

Christian Brabandt

unread,
Jul 13, 2025, 3:39:58 AM7/13/25
to vim...@googlegroups.com, vim...@vim.org
Hi,
I am afraid, I won't be of much help here, but you have been looking at
a quite complex problem. I personally don't see myself capable of doing
such complex changes that have the ability to cause regressions in other
parts of the code.

Also note, that the win_line() function needs to stay in sync with e.g.
the chartabsize functions, otherwise the cursor movements get out of
sync with the characters displayed on the screen and the cursor may end
somewhere else.

Further comments further down:

On Sa, 12 Jul 2025, 'Ian' via vim_dev wrote:

> 2. How do you deal with fixing a bug that spans multiple subsystems?
>
> Also, I'm not just talking about maintaining the project, I'm
> fascinated with the idea of someone, not familiar with the code, and
> adding a new somewhat complex feature they need (e.g. concealing is
> pretty complex), without having to backtrack all Vim's history and
> read everything to understand a small part.

Yes, concealing is quite complex and is still not working as expected.
Try to click with a mouse at a character where this lines contains
concealed characters

> 3. So how did you tackle reading the source for the first time?

I am old school. I grep around to find interesting places. Sometimes I
also just go directly into the debugger.

>
> 4. And after being involved for some time, do you have any
> suggestions you would have liked to have known in the
> beginning?

Yes, Vims source code can be overwhelming. Don't let that scare you
away, but you will need a lot of patience to understand possible
interactions with different subsystems.


Thanks,
Christian
--
Sigmund Freud is alleged to have said that in the last analysis the entire field
of psychology may reduce to biological electrochemistry.
Reply all
Reply to author
Forward
0 new messages