4coder » Forums » Useful custom functions
Lucas89
19 posts
#7379 Useful custom functions
2 years, 6 months ago Edited by Lucas89 on June 22, 2016, 2:42 p.m.

ratchetfreak
instead of moving the whole range up, why not move the line above the range down below the range (and vice versa)


I'm glad I decided to post these ideas on the forums.
I've been using C for just over a week now, so sometimes I focus too much on the language and can get stuck looking for a specific solution to a problem.

My solution works, but I like yours better so I'll get onto that after I've implemented my other required functionality :)
Mr4thDimention
Allen Webster
439 posts / 2 projects

Heyo

#7380 Useful custom functions
2 years, 6 months ago

I know the docs are abysmal so here's a tip, the "refresh" calls are only necessary after you call an exec_command that changes the state of the view. So for instance lucas_delete_line could be written as:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
View_Summary view = app->get_active_view(app);

app->view_set_mark(app, &view, seek_line_char(view.cursor.line, 0));
app->view_set_cursor(app, &view, seek_line_char(view.cursor.line, 65536), 1);
//app->refresh_view(app, &view);
exec_command(app, delete_range);
exec_command(app, delete_char);
app->refresh_view(app, &view);
app->view_set_cursor(app, &view, seek_line_char(view.cursor.line, 65536), 1);
//app->refresh_view(app, &view);


Also, in the next version, as apart of my work to cut down on the API cruft, the refresh is actually gone, and replaced with this helper:

1
2
3
4
void
refresh_view(Application_Links *app, View_Summary *view){
    *view = app->get_view(app, view->view_id, AccessAll);
}


So, as you can see, it literally just does another get so that your local copy is up to date.
Lucas89
19 posts
#7381 Useful custom functions
2 years, 6 months ago Edited by Lucas89 on June 23, 2016, 12:01 a.m.

Thanks for the tip :)
I've edited my previous posts to remove useless calls to `refresh_view`.

I'm writing these things as I need them while I do my work, so I'm mostly just guessing how to use the entire API.
It's starting to make more sense to me now, but it's useful to know these things so I can tidy up my code a bit.

I'm starting to run out of things I want to add now, but here is the latest.
When I type (, { or [ I like it to automatically insert the closing ), } or ].
In addition when the cursor is on a ), } or ], and I type the same character I like it to just skip the character, so this is what I came up with:

(This uses the `seek_char` function from this post)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
void
write_companion_character(Application_Links *app, char companion)
{
    View_Summary view = app->get_active_view(app);

    exec_command(app, write_character);
    app->refresh_view(app, &view);

    Buffer_Summary buffer = app->get_buffer(app, view.buffer_id);
    int pos = view.cursor.pos;

    app->buffer_replace_range(app, &buffer, pos, pos, &companion, 1);
    exec_command(app, move_left);
}

void
write_or_skip_character(Application_Links *app, char character)
{
    View_Summary view = app->get_active_view(app);

    if (view.cursor.pos == seek_char(app, view.cursor.pos, character, 1))
    {
        exec_command(app, move_right);
    }
    else
    {
        exec_command(app, write_character);
    }
}

CUSTOM_COMMAND_SIG(lucas_write_bracket_pair)
{
    write_companion_character(app, ')');
}

CUSTOM_COMMAND_SIG(lucas_write_brace_pair)
{
    write_companion_character(app, '}');
}

CUSTOM_COMMAND_SIG(lucas_write_square_pair)
{
    write_companion_character(app, ']');
}

CUSTOM_COMMAND_SIG(lucas_write_close_bracket)
{
    write_or_skip_character(app, ')');
}

CUSTOM_COMMAND_SIG(lucas_write_close_brace)
{
    write_or_skip_character(app, '}');
}

CUSTOM_COMMAND_SIG(lucas_write_close_square)
{
    write_or_skip_character(app, ']');
}

bind(context, '(', MDFR_NONE, lucas_write_bracket_pair);
bind(context, '{', MDFR_NONE, lucas_write_brace_pair);
bind(context, '[', MDFR_NONE, lucas_write_square_pair);

bind(context, ')', MDFR_NONE, lucas_write_close_bracket);
bind(context, '}', MDFR_NONE, lucas_write_close_brace);
bind(context, ']', MDFR_NONE, lucas_write_close_square);


Is there a built in function to get the character at the cursor, or next to the cursor etc?

As you can see, right now I use my own `seek_char` function a lot to compare positions, but being able to do something like `char_at_cursor(view.cursor)` or `char_after_cursor(view.cursor)` would be really useful.
Mr4thDimention
Allen Webster
439 posts / 2 projects

Heyo

#7385 Useful custom functions
2 years, 6 months ago

Are you familiar with the function "buffer_read_range"? It lets you read out text from an arbitrary range within the buffer. So to get the character at the cursor you could do:

1
2
3
4
5
6
static char
get_char(Application_Links *app, Buffer_Summary *buffer, int pos){
    char result = 0;
    app->buffer_read_range(app, buffer, pos, pos+1, &result);
    return(result);
}
Lucas89
19 posts
#7387 Useful custom functions
2 years, 6 months ago

Mr4thDimention
Are you familiar with the function "buffer_read_range"? It lets you read out text from an arbitrary range within the buffer.


I didn't see that one. When I had a look through the header files I think I was focusing on words like 'seek' and 'view' so even if I did see it I must have just skipped over it without thinking.

Thanks for letting me know about it!
I can go back and replace some of my own functions with a call to `buffer_read_range` now :)
Yam
James Fulop
21 posts / 1 project

None

#7402 Toggle between a period and arrow
2 years, 6 months ago Edited by James Fulop on June 26, 2016, 8:11 a.m.

Here's one I use all the time, just switches a period to an arrow or vice versa.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
CUSTOM_COMMAND_SIG(james_toggle_period_arrow)
{
    String cursor_character;//character under the cursor
    Buffer_Summary buffer;
    View_Summary view;

    view = app->get_active_view(app, AccessOpen);
    buffer = app->get_buffer(app, view.buffer_id, AccessAll);

    cursor_character.str = (char*)app->memory;
    cursor_character.size = 1;

    app->buffer_read_range(app, &buffer, view.cursor.pos, view.cursor.pos + 1, cursor_character.str);

    if (cursor_character.str[0] == '.')
    {
        app->buffer_replace_range(app, &buffer, view.cursor.pos, view.cursor.pos + 1, "->", 2);
    }
    else if (cursor_character.str[0] == '-')
    {
        app->buffer_replace_range(app, &buffer, view.cursor.pos, view.cursor.pos + 2, ".", 1);
    }
    else if (cursor_character.str[0] == '>')
    {
        app->buffer_replace_range(app, &buffer, view.cursor.pos - 1, view.cursor.pos + 1, ".", 1);
    }
}



None
ratchetfreak
426 posts
#7404 Useful custom functions
2 years, 6 months ago

In name of robustness I'd have read a char on either side of the cursor and made sure there was an arrow before replacing.

If buffer read range doesn't crash on out of bounds read it's pretty simple. otherwise you'd need to adjust the call based on whether the cursor is at the start or end of the buffer.
Mr4thDimention
Allen Webster
439 posts / 2 projects

Heyo

#7412 Useful custom functions
2 years, 6 months ago

If you do an out of range read, the read will fail. The fail is indicated as a zero return value from buffer_read_range.
MandleBro
Jack Mott
112 posts / 1 project

Web Developer by day, game hobbyist by night.

#7432 Useful custom functions
2 years, 6 months ago

Would it be possible to make a custom function to pop to the matching header file when in a C/cpp file, and vice versa?
The idea would be a recursive search through the folder and any subfolders looking for a .h/.cpp with the same name. This is really handy in visual studio.

If the necessary things are exposed to make that happen I'll have a go at it.
Mr4thDimention
Allen Webster
439 posts / 2 projects

Heyo

#7438 Useful custom functions
2 years, 6 months ago

Yes this is definitely possible.

You can get the buffer's file name. You can then use the string library to make a copy with the changed extension, or you can do that by hand obviously. Then you can use the app->directory_cd function or the app->get_file_list/app->free_file_list functions to explore the file system. Finally you can use app->create_buffer or the helper view_open_file to open the file.
Marchin
5 posts
#17039 Useful custom functions
3 weeks, 3 days ago

Hi, i'm new to 4coder and i wanted to create the "newline_above/below" functions like Lucas has. I understand the API has changed since then. I read the documentation to try updating it but i failed. Here is what i currently have

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
CUSTOM_COMMAND_SIG(insert_newline_above)
{
    View_Summary view = app->get_active_view_(app, AccessAll);
    exec_command(app, move_up);
    refresh_view(app, &view);
    exec_command(app, seek_end_of_line);
    refresh_view(app, &view);
    exec_command(app, write_and_auto_tab);
    refresh_view(app, &view);
}

CUSTOM_COMMAND_SIG(insert_newline_below)
{
    View_Summary view = app->get_active_view_(app, AccessAll);
    exec_command(app, seek_end_of_line);
    refresh_view(app, &view);
    exec_command(app, write_and_auto_tab);
    refresh_view(app, &view);
}
mrmixer
Simon Anciaux
519 posts
#17042 Useful custom functions
3 weeks, 2 days ago

write_and_auto_tab insert the character used to call the command as text. Unless you bind the command to '\n' it's not going to create a new line. You can use write_string to write a new line character instead. And since you don't use the View_Summary struct in the function there is no need to create and refresh it.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
CUSTOM_COMMAND_SIG(insert_newline_above)
CUSTOM_DOC( "Insert a new line above the current line." )
{
    exec_command(app, move_up);
    exec_command(app, seek_end_of_line);
    write_string(app, make_lit_string( "\n" ));
}

CUSTOM_COMMAND_SIG(insert_newline_below)
CUSTOM_DOC( "Insert a new line below the current line." )
{
    exec_command(app, seek_end_of_line);
    write_string(app, make_lit_string( "\n" ));
}
Marchin
5 posts
#17043 Useful custom functions
3 weeks, 2 days ago

Ohh i see, that works perfectly, thank you very much :).