4coder»Forums
Andrew Chronister
194 posts / 1 project
Developer, administrator, and style wrangler
Quick Qs
As I'm working on the vim layer I often come across small questions of functionality / documentation ambiguity that I end up asking allen about in chat; Since he's not always online, and others might benefit from the clarification, I figured I'd make a thread here.

Today's Qs:

- In a Full_Cursor, what system are the X/Ys in? Is it relative to the screen or to the view? Is the unit 1 pixel or 1 line/character? Is y up or down? :P

- Still not totally clear on what it means to get a view using a certain permission. If I try to open a narrow-permission view using a broad-permission flag, does the call fail or do I just get the view with narrow permissions? Likewise, if I try to open a broad-permission view with a narrow-permission flag, will calls made assuming the broad permissions succeed?

Cheers,
- Andrew
Allen Webster
476 posts / 6 projects
Heyo
Quick Qs
Edited by Allen Webster on Reason: more clarification
X & Y coordinates are in pixels, some are relative to the view, others are relative to the 4coder window. Basically the rule is that Full_Cursor is always relative to the view, but everything else is relative to the window for instance the mouse is relative to the window, and to go from mouse -> buffer X & Y you should get the view's position on the screen, find out how much it scrolled, and do the arithmetic on the mouse. I think there is a helper for this but I can't remember its name off the top of my head (global_point_to_view_point or something like that).

Permissions are meant to make it easy for the author to write commands that behave as expected for writable buffers vs read only buffers. Some commands logically work without write access to the buffer, for instance moving the cursor or copying to the clipboard. Other commands logically need write access such as write_character or paste. The goal of the API is to make it easy to get it right without having to ask for the buffer multiple times. Consider these four cases:

  • writable buffer & command only needs read access
  • writable buffer & command needs write access
  • read only buffer & command only needs read access
  • read only buffer & command needs write access

There is only one case of those four where you want the command to fail, the last case. Now the proper way to set up this API is probably to have the author of the command use constants that indicate whether the command is a logical 'read only' command or a 'needs write access' command, and then return the buffer if it is appropriate. What I have instead is a near approximation of this API where you specify that you want 'AccessOpen' when you are writing a command that needs write access and you specify 'AccessProtected' when you are writing a command that can get by with read only access.

So AccessProtected will always* return the buffer or view, even if it is writable, whereas AccessOpen will not return a read only buffer. In terms of 'narrowness' the confusion might be that 'protected' sounds narrow, but write only access is the more narrow case.

The buffer or view you get back is not at all altered by the access level you request. The only thing that changes when you change your access level is whether or not the buffer or view is returned to you at all. Once you have the buffer or view, all the API calls work on it no matter what it's read/write flags say. So you can deliberately get a read only buffer and write to it if that's what you want to do, the API is just meant to make it easy to do the thing you *probably* wanted to do.

*There is actually another rule when it comes to views. Usually views just pass along their buffer's access state. The purpose of this is because you can do a lot with just a view and again the goal is to minimize how much the author has to think about this, so instead of forcing them to get the buffer and see the result, the view just follows the rule that its buffer follows. However, views can also get into another state, where they are showing a GUI instead of the file they are associated with. In a case like this you usually don't want things like standard navigation commands to effect the buffer that you can't see. So when the view is in this state AccessProtected will not return the view. If you want to always get the view back, even when it is hiding its buffer, then you should use AccessAll. AccessAll also works when you pass it to a buffer, and I often just pass AccessAll to everything until I know for sure what the logical command type is. Finally there is another constant called AccessHidden, which I believe ONLY returns views that are hiding their file and showing a GUI, but that was just a bad API and since GUI's are changing soon anyway I recommend never using it.
Andrew Chronister
194 posts / 1 project
Developer, administrator, and style wrangler
Quick Qs
Edited by Andrew Chronister on
Sweet, that helps, thanks.

I encountered what I believe to be an internal bug in 4.0.17 while testing things out. It could be an issue with how I'm using the API but the crash occurs inside 4coder so I'm not certain. For context, I've only repro'd in the 4vim "move_backward_word_start" function, which is failing somewhere deep in basic_seek().

Memory dump available here, and relevant custom.dll and .pdb.
Allen Webster
476 posts / 6 projects
Heyo
Quick Qs
So I took a look, and I think all that went wrong is that hooks are the worst.

If you use any default features you need to call
1
default_4coder_initialize(app);

at the beginning of the startup hook.

This initializes a few things, including a global stack allocator that the basic_seek needs still. It also runs 'config.4coder' If you don't want the config file system to effect your vim system you can instead just call the poorly named:
1
init_memory();


Tomasz Różański
11 posts
Quick Qs
Mr4thDimention

If you use any default features you need to call
1
default_4coder_initialize(app);

at the beginning of the startup hook.


Brilliant! I was experimenting with my very first startup hook when 4coder went full crash mode. This one line of code fixed it automagically. Kudos to you, sir.
Allen Webster
476 posts / 6 projects
Heyo
Quick Qs
Hahaha. I would say it's more like anti-Kudos to me. I've got to sanitize the default-custom API to avoid wasting everyone's time with this issue, but the based API doesn't really give me a way to do that.
Scott Hunt
41 posts
Father, Thinker, Mechanical Engineer @NASA, and C/C++ Hobby Enthusiast / @TexxStudio
Quick Qs
Probably a simple one. Any non-super way to have auto-indentation ignore opening bracket on extern "C"? Currently it pushes all downstream function prototypes, struct definitions and other items out a tab.

#ifdef __cplusplus
extern "C" {
#endif

Thanks,
Scott
19 posts
Quick Qs
Edited by simonWasHere on
Not in front of my computer to test this, and a bit hacky, but how about:

1
#define EXTERNC extern "C" {


edit: actually, now I think about it more it probably won't work because the indentation system will think it is a statement without a semicolon at the end :(

2nd edit: in fact it does seem to work, and you can also do the perhaps even nastier:

1
2
3
4
5
6
7
#ifdef CPP
extern "C" {
#endif
    
#ifdef NOT_DEFINED
}
#endif

Allen Webster
476 posts / 6 projects
Heyo
Quick Qs
The method:
1
2
#define EXTERNC extern "C" {
#define EXTERNC_END }

Is probably the best option right now, I can't think of a better equivalent option.
Scott Hunt
41 posts
Father, Thinker, Mechanical Engineer @NASA, and C/C++ Hobby Enthusiast / @TexxStudio
Quick Qs
Thanks Simon and Allen, works like a charm and simple.