4coder/SUPERREADME_body.txt

437 lines
18 KiB
Plaintext

-------------------------------------
BUILDING 4coder_custom
-------------------------------------
To customize 4coder you have to build 4coder_custom.dll. The batch file buildsuper.bat will
compile the dll for you if you have visual studio installed. If you have an old version, use
the example to figure out how to get your old setup working in the new system.
As you create your customizations keep in mind that this API is still in development.
I will do what I can to keep your customizations working as I settle on an API, but some
updates may deeply break your code.
-------------------------------------
SOME DOCUMENTATION
-------------------------------------
See comments in 4coder_default_bindings.cpp for more detailed information.
Functions to implement (optional in the dll, but required if you are using buildsuper.bat):
get_bindings
NEW IN 4.0.7
================
Moved a lot of commands to the custom side. Almost all of them have the same name
they use to have just without cmdid_ on the front. Other than that cmdid_backspace
became backspace_char, and cmdid_delete became delete_char.
Left and right clicks are now associated to key codes for bindings
app->get_mouse_state returns the current mouse
NEW IN 4.0.5:
================
app->buffer_compute_cursor to get cursor position info without moving the cursor
can now use f keys for bindings
NEW IN 4.0.3:
================
The build system for customizations has been changed. There is no longer a 4coder_custom.cpp.
Instead the default customizations are in 4coder_default_bindings.cpp. The batch file takes a parameter
that tells it what file to treat as the target for building, if the parameter is not defined it defaults to
4coder_default_bindings.cpp.
NEW IN 4.0.2:
================
#include "4coder_default.cpp" at the top of your own file to get a lot of the default functions
such as incremental search, various word boundry seeks, and so on.
app->buffer_seek_string_insensitive(app, &buffer, start, str, len, seek_forward, &out);
Exactly the same as app->buffer_seek_string, but the matching rule is case insensitive
app->get_command_input(app);
Returns a User_Input that represents the input event that triggered the current command.
app->print_message(app, str, len);
Put a string into the *message* buffer.
OLD API DOC:
================================================================
There is an API available to custom commands and hooks, described at length here.
The system has two main data types, buffers and views. A buffer contains text,
undo history, and tokens. Views looks at a file and has a cursor a mark a highlight
and so on. The view and buffer are not the same because not all buffers are viewed,
and there may be two views viewing the same buffer.
================
app->memory;
app->memory_size;
Here you get 2mb of memory that are completely yours to do whatever you need to do. This is for
those who found that malloc was not working for their allocation needs. There are currently no
allocation helpers so you'll have to figure out how to manage it.
================
app->directory_get_hot(app, out, capacity);
Fills the out buffer with the "hot directory", which is the last directory 4coder has visited.
If it cannot write out the whole name it writes only what it can.
Always returns the length of the current hot directory in bytes.
================
app->file_exists(app, filename, len);
Filename can be either a full path or a relative path.
Returns whether the file exists.
================
app->directory_cd(app, dir, &len, capacity, rel_path, rel_len);
Looks at dir and updates it's contents as if a "cd" command had been cone from that directory.
if rel_path is ".." then the .. is not appended as a string, the directory is shortened if possible.
Returns false if the directory does not exist or if ".." was specified but it is impossible to back up,
returns true otherwise.
================
app->get_file_list(app, dir, len);
If the directory exists, generates a list of all files and folders in that directory. All File_List structs
generated by get_file_list should be freed with free_file_list.
Returns a File_List struct listing all files and folders in dir, or an empty list if dir does not exist or is empty.
================
app->free_file_list(app, list);
Frees a File_List created by get_file_list.
================
struct File_List;
The important fields are:
File_Info *infos;
int count;
count is the number of File_Info structs in the File_Info array.
struct File_Info;
String filename;
int folder;
folder is 1 or 0 to indicate whether the entry is a file or folder.
filrname is a string which may be editted, but not resized, that is filled with the name of a file or folder.
================
app->get_buffer_first(app);
app->get_buffer_next(app, &buffer);
The new method for looping over buffers is:
for (Buffer_Summary b = app->get_buffer_first(app);
b.exists;
app->get_buffer_next(app, &b)) { }
================
app->get_buffer(app, index);
Returns a Buffer_Summary which contains information about a buffer and acts as the
handle to the buffer for other functions. The parameter index can be anything in the
range [0,max) where max comes from app->get_buffer_max_index
================
app->get_active_buffer(app, index);
Returns a Buffer_Summary obtained from the active panel.
================
app->get_buffer_by_name(app, str, len);
Returns a Buffer_Summary who's "full source path" exactly matches str. There is
currently no way to look a buffer up by "live name" the short name shown on the top bar.
Buffers that are not associated with real files such as *compilation* have their "full source path"
name set to the same value as their live name, therefore you can get a *compilation* buffer with
this API by the name "*compilation*".
================
app->refresh_buffer(app, &buffer);
If a changes are made to a buffer the changes are not necessarily reflected in your Buffer_Summary,
use this to get updated information on the buffer. All commands in the low level API will udpate
your Buffer_Summary if a change is made, so refreshing afterwards is not necessary in that case.
The function returns 1 on success and 0 on failure.
================
app->buffer_seek_delimiter(app, &buffer, start, delim, seek_forward, &out);
Starting from start, seeks forward or backward until the first occurance of delim,
the pointer out is filled with the position of the delimiter.
If no delimiter is found out is filled with -1 for backward seeks and the size of the buffer on forward seeks.
The function returns 1 on success and 0 on failure.
================
app->buffer_seek_string(app, &buffer, start, str, len, seek_forward, &out);
Starting from start, seeks forward or backward until the first occurance of str,
the pointer out is filled with the position of the delimiter.
If no str is found out is filled with -1 for backward seeks and the size of the buffer on forward seeks.
The function returns 1 on success and 0 on failure.
================
app->buffer_read_range(app, &buffer, start, end, buffer_out);
Fills buffer_out with the text that the buffer contains in the range [start,end) it is your responsibility
to ensure that the memory pointed to by buffer_out is at least (end - start) bytes.
The function returns 1 on success and 0 on failure.
================
app->buffer_replace_range(app, &buffer, start, end, str, len);
Replaces the text in the range between start and end with the the text in str. It is allowed that
start == end so that you may insert str without replacing anything, and it is allowed that len == 0
so that you may delete text without replacing it with anything. These edits are tracked by history
and cause an update in the tokens if there are tokens. Your buffer will be updated to reflect
the change in the buffer caused by this edit.
The function returns 1 on success and 0 on failure.
================
View_Summary:
There use to be a lot of different view types and only "file views" were exposed in the API.
As of alpha 4 there are only views and you can always get a view.
Besides renaming the struct, there is also a change in the meaning of the "buffer_id" field.
A view can have a buffer attached, but not currently be looking at that file.
All of the following indicate the buffer associated with the view:
buffer_id
locked_buffer_id
hidden_buffer_id
These ids are nulled out to indicate that access at a particular level is not available.
buffer_id -
This is null if the file is not visible in the view OR if the view is locked.
A view is only locked right now for read only buffers (compilation output).
locked_buffer_id -
This is null only if the file is not visible.
hidden_buffer_id -
This is never null.
In normal circumstances you can just use buffer_id and your code will automatically do
nothing when you try to edit a buffer you should not.
If what you are writing is unusual and it SHOULD edit a buffer even if it is locked or
hidden, then you can use the other ids to get deeper access.
================
app->get_view_first(app);
app->get_view_next(app, &view);
The new method for looping over views is:
for (View_Summary v = app->get_view_first(app);
v.exists;
app->get_view_next(app, &v)) { }
================
app->get_file_view(app, index);
Returns a View_Summary which contains information about a file view and acts as
the handle to the file view for other functions. The parameter index can be anything in the
range [0,max) where max comes from app->get_view_max_index
================
app->get_active_file_view(app, index);
Returns a View_Summary obtained from the active panel.
================
app->refresh_file_view(app, &view);
If a changes are made to a view the changes are not necessarily reflected in your View_Summary,
use this to get updated information on the view. All commands in the low level API will udpate
your View_Summary if a change is made, so refreshing afterwards is not necessary in that case.
The function returns 1 on success and 0 on failure.
================
struct Buffer_Seek;
This struct specifies how to set a position in a file, it is in 4coder_buffer_types.h look there to see
all the options.
The following helpers will return Buffer_Seek structs for you:
+ To seek to a particular position (0-based-indexing) use seek_pos(pos)
+ To seek to a particular xy you either want seek_wrapped_xy(x, y, round_down)
or seek_unwrapped_xy(x, y, round_down). Wrapped vs unwrapped refers to whether
line wrapping is on. Both seek types are valid whether or not lines are wrapped, but
the results may be surprising if you do not match the correct type. round_down is usually 0,
and the effect is subtle, it has to do with whether the y position should be rounded down or rounded
to the nearest line. x and y are specified in pixels to move the y up or down a while line use view.line_height.
+ To seek to a particular line and character index on that line use seek_line_char(line, char_index)
================
app->view_set_cursor(app, &view, seek, set_preferred_x)
Updates the cursor location in this view. See information on the Buffer_Seek struct above for more
information. set_preferred_x if true set's the "preferred_x" of view to match the x of the cursor. The
preferred_x is the x the cursor tries to stay at as it moves up and down. Most cursor motion does set
the preferred_x.
The function updates the data in the View_Summary.
The function returns 1 on success and 0 on failure.
================
app->view_set_mark(app, &view, seek)
Updates the mark location in this view. See information on the Buffer_Seek struct above for more
information.
The function updates the data in the View_Summary.
The function returns 1 on success and 0 on failure.
================
app->view_set_highlight(app, &view, start, end, on)
If on is 0 this call turns the highlight off.
If on is 1 this call turns the highlight on and sets the highlight to range from start to end.
While the highlight is on the view will follow the end of the highlight and the cursor will be hidden.
Be sure to turn the highlight off when you're done with it!
The function returns 1 on success and 0 on failure.
================
app->view_set_file(app, &view, file_id)
Set this view to look at a different buffer (the buffer must already be opened and have a file_id).
The function updates the data in the View_Summary.
The function returns 1 on success and 0 on failure.
================
app->get_user_input(app, get_type, abort_type);
This is a blocking operation that will allow 4coder to continue operating. The next input event
will be intercepted by this command, and will not be interpreted as normal. Input events include:
pressing a key
clicking left or right
rolling the mouse wheel
moving the mouse
The get_type flags specify a filter of what types of input you'd like to be notified about. Even if you
are not notified about keyboard input events, they are still not passed to any other systems to be
interpreted as commands or text input. The same is true for mouse input with the exception of
panel resizing, which can be done durring a command.
The abort_type flags specify the set of inputs you'd like to get an abort message on. It is good to
specify abort flags so that the system will know when your command is about to finish up. After
getting an abort message you can continue to do other work and call commands with exec_command
but you should not call app->get_user_input again. It will not cause an error if you do, but it could lead
to unexpected behavior. And in the future it might be that it IS an error to call get_user_input after an abort.
================
struct User_Input;
type: either UserInputKey or UserInputMouse
abort: true if this is an abort message, false otherwise
key: information about a key event
mouse: information about a mouse event
command: if this event would be translated into a command normally, this is the command.
Use CommandEqual to compare two commands in a typeless way since
cmdid_* and custom commands have different types.
================
key is of type:
struct Key_Event_Data;
keycode: always set to exactly the key that was pressed
character: a translation of the key press that takes into account Shift/Control/Alt/AltrGr/Caps-Lock
character_no_caps_lock: same as "character" but doesn't take Caps-Lock into account
modifiers[i]: flags for modifiers were held when this key was pressed
i: MDFR_SHIFT_INDEX, MDFR_CONTROL_INDEX, MDFR_ALT_INDEX, MDFR_CAPS_INDEX
TIP! Don't use MDFR_SHIFT, MDFR_CTRL, MDFR_ALT in the array! Those are bit masks, not indices!
================
mouse is of type:
struct Mouse_State;
l - whether the left button is down
r - whether the right button is down
press_l - whether the left button was just put down
press_r - whether the right button was just put down
release_l - whether the left button was just released
release_r - whether the right button was just released
wheel - values of 1, 0, -1. Does not report wheel amount, only direction.
out_of_window - 1 if the mouse is outside of the 4coder window, 0 otherwise
x, y - position of the mouse relative to the 4coder window
================
app->start_query_bar(app, &bar, 0);
Notify 4coder that you are using a Query_Bar and you want it rendered onto the screen.
While the query bar is still running any changes you make to prompt or string will be
shown right away, you don't have to ask 4coder to update it's bar because it reads straight
out of your Query_Bar.
If the pointer you pass goes bad, because a stack frame ends or you otherwise no longer
need the bar, you should call app->end_query_bar(app, &bar); so that 4coder doesn't try
to render a query bar from garbage memory. If the command finishes and there are query
bars that haven't been ended, 4coder automatically ends them.
There is a limit of 8 simultaneous queries bars and right now only file views support them.
The abillity to make a Query_Bar in other views including the empty view will come in the future though.
The 0 is there because Iintend to add flags for query bars in the future,
for modifying their appearance and behavior.
Returns 1 if it successfully started a query bar.
================
app->end_query_bar(app, &bar);
See start_query_bar for details.
================
Theme changing API
app->change_theme(app, name, len)
Set the theme to one of the prebuilt themes by name.
app->change_font(app, name, len)
Set the font to one of the fonts by name (not by ttf file name, by the name in the list).
app->set_theme_colors(app, colors, count)
Set colors of the current theme by tag color pairs.
Changes from 3.3 to 3.4:
-exposed command word complete
Changes from 3.2 to 3.3:
-exposed command build and added several example uses to the example file
-introduced directory navigation API
-slight tweaks to the API, moving away from macro translation
Changes from 3.1 to 3.2:
-exposed new commands relating to auto-tab
-removed old commands for whitespace cleaning
Changes from 3.0 to 3.1:
-start_hook eliminated, now bound through set_hook durring the get_bindings function
-vanilla_keys changed so that specific keys can be overriden
-you can now specify your own maps
-new parameter stack for communicating to some commands
-fulfill_interaction has been removed (push_parameter will be used to achieve it's effect)
-new hook for opening files, intended for file setting configuration
-exposed the new commands relating to history and the timeline scrub bar
Changes from 2.2.3 to 3.0:
-exposed the new undo / redo commands
Changes from 2.2.2 to 2.2.3:
-The binding API is remarkably different, but I included a
small set of helpers with this API that make the API look
almost exactly the same.
-you can now specify size for custom fonts
-you can now fulfill interacive commands
-fixed a bug that existed when some commands were used in exec_command
Changes from 2.2.1 to 2.2.2:
-added MDFR_SHIFT
-removed redundant keys from Key_Codes struct
-added bind_me
-added exec_command
-put bind, bind_me and exec_command into a struct
-added Custom_Command_Function
-added Start_Hook_Function