[Custom Commands] Include Guard + cpp caster

The code is pretty messy, and I didn't check to see if you already had string operations somewhere else before starting.

Currently guards to throw an error if it finds the file to be included multiple times, can make it do a more traditional guard fairly easy if you would prefer.

Hope someone here has use for it :)

http://i.imgur.com/DpeWLol.gifv

 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
void str_cpy(char* dst, const char* src,unsigned len) {
    for(;len;--len,++src,++dst)
        *dst = *src;
}

void replace_chars(char* str, unsigned len, char find, char replace) {
    for(;len;--len,++str)
        if(*str == find)
        *str = replace;
}

void to_upper(char* str,unsigned len){
    for(;len;--len,++str)
        if(*str >= 0x61 && *str <= 0x7A)
        *str -= 0x20;
}

CUSTOM_COMMAND_SIG(include_guard_header){
    uint32_t access = AccessOpen;
    
    View_Summary view = get_active_view(app, access);
    Buffer_Summary buffer = get_buffer(app, view.buffer_id, access);
    
    char filenamebuf[0x100];
    char cbuffer[0x200];
    String str = make_fixed_width_string(cbuffer);
    
    unsigned len = 0;
    char* fileshort = buffer.file_name + buffer.file_name_len;
    for(;*fileshort != '/'; --fileshort, ++len)
        ;
    fileshort++; len--;
    
    str_cpy(filenamebuf, fileshort, len);
    replace_chars(filenamebuf, len, ' ', '_');
    replace_chars(filenamebuf, len, '.', '_');
    to_upper(filenamebuf, len);
    String fstr = make_string(filenamebuf, len);
    
    append(&str, "#ifdef ");
    append(&str, fstr);
    append(&str, "\n#error \"File included multiple times.\"\n#endif\n#define ");
    append(&str, fstr);
    
    write_string(app, str);
}

Edited by Gregory on
Really nice implementation. I might rip some of this and make an official version of this soon because it's a good feature that a lot of people would probably want. Plus I will be able to make it work through the '4coder_string.h' stuff.

By the way, I normally don't see include guards used to generate errors when a file is included multiple times, but it's interesting. If you don't mind, is there any particular reason you prefer that over the include guard that just prevents the body of the file from being instantiated more than once?
Its something I have picked up for include files to be aware of looping dependencies, can help compile time (a minuscule amount), but mostly just forces me to not be lazy with including things haha

For files that are just type decls or something i dont mind being everywhere, i just use #pragma once which isnt really in need of a macro imo

Edited by Gregory on
Well I'm thinking about setting up a feature to fill new header files automatically. However having it as a built in command is going to be useful on occasion too.

I'll have to try your include guard system in my next project, it sounds interesting to me.
Wrote another command to set up the cpp casts for me, going to try to kick the habit of using c casts everywhere.

http://i.imgur.com/XgDy9fm.gifv

in the prompt:

s = static_cast
d = dynamic_cast
c = const_cast
r = reinterpret_cast


Most of it was shamelessly copypasta'd from the #if 0 #endif command.

I was thinking, that for situations where you have T v1 = cast<T>(v2); it could deduce the type you are casting to, curious as to how you would approach that.

 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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
CUSTOM_COMMAND_SIG(write_cpp_cast) {
    const char sig_static[]       = "static_cast<>(";
    const char sig_dynamic[]      = "dynamic_cast<>(";
    const char sig_const[]        = "const_cast<>(";
    const char sig_reinterpret[]  = "reinterpret_cast<>(";
    const char sig_end[]          = ")";
    
    const int sz_static           = sizeof(sig_static) - 1;
    const int sz_dynamic          = sizeof(sig_dynamic) - 1;
    const int sz_const            = sizeof(sig_const) - 1;
    const int sz_reinterpret      = sizeof(sig_reinterpret) - 1;
    const int sz_end              = sizeof(sig_end) - 1;
    
    
    char type[8];
    const char* cb;
    int sz;
    
    Query_Bar bar;
    bar.prompt = make_lit_string("Cast type: ");
    bar.string = make_fixed_width_string(type);
    
    if (!query_user_string(app, &bar)) return;
    end_query_bar(app, &bar, 0);
    
    switch(type[0]){
        case 's': {
            cb = sig_static;
            sz = sz_static;
        }break;
        case 'd': {
            cb = sig_dynamic;
            sz = sz_dynamic;
        }break;
        case 'c': {
            cb = sig_const;
            sz = sz_const;
        }break;
        case 'r': {
            cb = sig_reinterpret;
            sz = sz_reinterpret;
        }break;
        default: {
            return;
        }
    }
    
    
    View_Summary view = get_active_view(app, AccessOpen);
    Buffer_Summary buffer = get_buffer(app, view.buffer_id, AccessOpen);
    
    Range range = get_range(&view);
    
    if (range.min < range.max){
        Buffer_Edit edits[2];
        char *str = 0;
        char *base = (char*)partition_current(&global_part);
        
        str = push_array(&global_part, char, sz);
        memcpy(str, cb, sz);
        edits[0].str_start = (int32_t)(str - base);
        edits[0].len = sz;
        edits[0].start = range.min;
        edits[0].end = range.min;
        
        str = push_array(&global_part, char, sz_end);
        memcpy(str, sig_end, sz_end);
        edits[1].str_start = (int32_t)(str - base);
        edits[1].len = sz_end;
        edits[1].start = range.max;
        edits[1].end = range.max;
        
        buffer_batch_edit(app, &buffer, base, global_part.pos, edits, ArrayCount(edits), BatchEdit_Normal);
        
        if(view.cursor.pos < view.mark.pos){
            view_set_cursor(app, &view, seek_line_char(view.cursor.line, view.cursor.character + sz - 2), 1);
        }
        else{
            view_set_cursor(app, &view, seek_line_char(view.mark.line, view.mark.character + sz - 2), 1);
        }
        
    }
}

Edited by Gregory on
Hmm detecting type is going to be a bit of a hack. The best I can think to do is get the index of the first and last characters on the line, which you can do with one of the helpers. Then you can use buffer_get_token_index to find out the range of tokens on the line. Use buffer_read_tokens to get those tokens and then try to parse it and see if it is a variable declaration, but you're on your own for that, and it won't be possible to get it exactly right without the full parse context, but it should be possible to get it right in the cases where you care about it.