this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge pull request #2174 from koltenpearson/vi-mode

Vi mode

authored by

Vadim Grigoruk and committed by
GitHub
fd13a408 3e495ab9

+975 -71
+1 -1
src/ext/history.h
··· 30 30 bool history_add(History* history); 31 31 void history_undo(History* history); 32 32 void history_redo(History* history); 33 - void history_delete(History* history); 33 + void history_delete(History* history);
+1 -1
src/studio/config.c
··· 246 246 .fullscreen = false, 247 247 .integerScale = INTEGER_SCALE_DEFAULT, 248 248 #if defined(BUILD_EDITORS) 249 - .emacsMode = false, 249 + .keybindMode = KEYBIND_STANDARD, 250 250 .devmode = false, 251 251 #endif 252 252 },
+902 -48
src/studio/editors/code.c
··· 63 63 } 64 64 } 65 65 66 - static void unpackState(Code* code) 66 + //if pos_undo is true, we set the position to the first charcter 67 + //that is different between the current source and the state (wanted undo behavior) 68 + //otherwise we set the position to the stored location (wanted redo behavior) 69 + //in either case if no change was detected we do not change the position 70 + //(this occurs when there are no undo's or redo's left to apply) 71 + static void unpackState(Code* code, bool pos_undo) 67 72 { 68 73 char* src = code->src; 74 + 75 + char* first_change = NULL; 76 + char* stored_pos = NULL; 77 + 69 78 for(CodeState* s = code->state, *end = s + TIC_CODE_SIZE; s != end; ++s) 70 79 { 80 + 81 + if (first_change == NULL && *src != s->sym) 82 + first_change = src; 83 + 71 84 if(s->cursor) 72 - code->cursor.position = src; 85 + stored_pos = src; 73 86 74 87 *src++ = s->sym; 75 88 } 89 + 90 + if (first_change != NULL) { 91 + 92 + //we actually will want to go the one before the first change, as if 93 + //we were about to make the change 94 + //ternary to make sure we don't go one before the beginning 95 + if (pos_undo) 96 + code->cursor.position = first_change == code->src ? code->src : (first_change - 1); 97 + 98 + else code->cursor.position = stored_pos; 99 + } 76 100 } 77 101 78 102 static void history(Code* code) 79 103 { 104 + //if we are in insert mode we want want all changes we make to be reflected 105 + //in the undo/redo history only when we leave it 106 + if (checkStudioViMode(code->studio, VI_INSERT)) 107 + return; 80 108 packState(code); 81 109 history_add(code->history); 82 110 } ··· 188 216 static void drawCursor(Code* code, s32 x, s32 y, char symbol) 189 217 { 190 218 bool inverse = code->cursor.delay || code->tickCounter % TEXT_CURSOR_BLINK_PERIOD < TEXT_CURSOR_BLINK_PERIOD / 2; 219 + 220 + if (checkStudioViMode(code->studio, VI_NORMAL)) 221 + inverse = true; 191 222 192 223 if(inverse) 193 224 { ··· 419 450 const tic_script_config* config = tic_core_script_config(tic); 420 451 return config_isalnum_(config, c); 421 452 } 453 + 422 454 423 455 static void setCodeState(CodeState* state, u8 color, s32 start, s32 size) 424 456 { ··· 964 996 setCursorPosition(code, column, line < lines - TEXT_BUFFER_HEIGHT ? line + TEXT_BUFFER_HEIGHT : lines); 965 997 } 966 998 999 + static void halfPageUp(Code* code) 1000 + { 1001 + s32 half = TEXT_BUFFER_HEIGHT / 2; 1002 + s32 column = 0; 1003 + s32 line = 0; 1004 + getCursorPosition(code, &column, &line); 1005 + setCursorPosition(code, column, line > half ? line - half : 0); 1006 + } 1007 + static void halfPageDown(Code* code) 1008 + { 1009 + s32 half = TEXT_BUFFER_HEIGHT / 2; 1010 + s32 column = 0; 1011 + s32 line = 0; 1012 + getCursorPosition(code, &column, &line); 1013 + s32 lines = getLinesCount(code); 1014 + setCursorPosition(code, column, line < lines - half ? line + half : lines); 1015 + } 1016 + 967 1017 static void deleteCode(Code* code, char* start, char* end) 968 1018 { 969 1019 s32 size = (s32)strlen(end) + 1; ··· 1312 1362 if (killSelection) 1313 1363 code->cursor.selection = NULL; 1314 1364 1315 - history(code); 1365 + //no call to history because it gets called in replaceSelection 1316 1366 } 1317 1367 1318 1368 static void copyFromClipboard(Code* code, bool killSelection) ··· 1358 1408 1359 1409 static void update(Code* code) 1360 1410 { 1411 + updateColumn(code); 1361 1412 updateEditor(code); 1362 1413 parseSyntaxColor(code); 1363 1414 } ··· 1365 1416 static void undo(Code* code) 1366 1417 { 1367 1418 history_undo(code->history); 1368 - unpackState(code); 1419 + unpackState(code, true); 1369 1420 1370 1421 update(code); 1371 1422 } ··· 1373 1424 static void redo(Code* code) 1374 1425 { 1375 1426 history_redo(code->history); 1376 - unpackState(code); 1427 + unpackState(code, false); 1377 1428 1378 1429 update(code); 1379 1430 } ··· 1457 1508 } 1458 1509 } 1459 1510 1460 - static void setFindMode(Code* code) 1511 + static void setFindOrReplaceMode(Code* code) 1461 1512 { 1462 1513 if(code->cursor.selection) 1463 1514 { ··· 1657 1708 { 1658 1709 code->anim.movie = resetMovie(&code->anim.show); 1659 1710 1660 - strcpy(code->popup.text, ""); 1711 + //so that in edit mode we can refer back to the most recently 1712 + //searched thing if we want 1713 + if (mode != TEXT_EDIT_MODE) 1714 + strcpy(code->popup.text, ""); 1661 1715 1716 + code->popup.offset = NULL; 1662 1717 code->popup.prevPos = code->cursor.position; 1663 1718 code->popup.prevSel = code->cursor.selection; 1664 1719 1665 1720 switch(mode) 1666 1721 { 1667 - case TEXT_FIND_MODE: setFindMode(code); break; 1722 + case TEXT_FIND_MODE: setFindOrReplaceMode(code); break; 1723 + case TEXT_REPLACE_MODE: setFindOrReplaceMode(code); break; 1668 1724 case TEXT_GOTO_MODE: setGotoMode(code); break; 1669 1725 case TEXT_BOOKMARK_MODE: setBookmarkMode(code); break; 1670 1726 case TEXT_OUTLINE_MODE: setOutlineMode(code); break; ··· 1750 1806 } 1751 1807 1752 1808 code->cursor.selection = NULL; 1753 - 1754 - history(code); 1755 1809 1756 1810 parseSyntaxColor(code); 1757 1811 } ··· 1885 1939 1886 1940 } 1887 1941 else addCommentToLine(code, getLine(code), size, comment); 1942 + 1943 + history(code); 1888 1944 } 1889 1945 1890 1946 static void dupLine(Code* code) ··· 1942 1998 return false; 1943 1999 } 1944 2000 2001 + static bool clipboardHasNewline() 2002 + { 2003 + bool found = false; 2004 + if (tic_sys_clipboard_has()) 2005 + { 2006 + 2007 + //from what I can see in other usage, this should be a 2008 + //null terminated string with the clipboard contents 2009 + char* clipboard = tic_sys_clipboard_get(); 2010 + 2011 + char* c = clipboard; 2012 + while(*c != 0) 2013 + { 2014 + if (*c == '\n') 2015 + { 2016 + found = true; 2017 + break; 2018 + } 2019 + 2020 + c++; 2021 + } 2022 + 2023 + tic_sys_clipboard_free(clipboard); 2024 + } 2025 + return found; 2026 + } 2027 + 2028 + static char* upStrStr(const char* start, const char* from, const char* substr) 2029 + { 2030 + const char* ptr = from-1; 2031 + size_t len = strlen(substr); 2032 + 2033 + if(len > 0) 2034 + { 2035 + while(ptr >= start) 2036 + { 2037 + if(memcmp(ptr, substr, len) == 0) 2038 + return (char*)ptr; 2039 + 2040 + ptr--; 2041 + } 2042 + } 2043 + 2044 + return NULL; 2045 + } 2046 + 2047 + static char* downStrStr(const char* start, const char* from, const char* substr) 2048 + { 2049 + return strstr(from, substr); 2050 + } 2051 + 2052 + 2053 + static void seekEmptyLineForward(Code* code) { 2054 + char* pos = code->cursor.position; 2055 + 2056 + //goto state machine, one of the few ways to use goto well 2057 + start: 2058 + if (*pos == '\0') goto end; 2059 + else if (*pos == '\n') { pos++; goto check; } 2060 + else { pos++; goto start; } 2061 + 2062 + check: 2063 + if (*pos == '\0') goto end; 2064 + else if (*pos == '\t') { pos++; goto check; } 2065 + else if (*pos == ' ') { pos++; goto check; } 2066 + else if (*pos == '\n') goto end; 2067 + else goto start; 2068 + 2069 + end: 2070 + code->cursor.position = pos; 2071 + updateColumn(code); 2072 + updateEditor(code); 2073 + 2074 + } 2075 + 2076 + static void seekEmptyLineBackward(Code* code) { 2077 + char* pos = code->cursor.position; 2078 + 2079 + if (pos == code->src) return; 2080 + else pos--; //need to start one behind so we don't match the one we are on 2081 + 2082 + //goto state machine, one of the few ways to use goto well 2083 + start: 2084 + if (pos == code->src) goto end; 2085 + else if (*pos == '\n') { pos--; goto check; } 2086 + else { pos--; goto start; } 2087 + 2088 + check: 2089 + if (pos == code->src) goto end; 2090 + else if (*pos == '\t') { pos--; goto check; } 2091 + else if (*pos == ' ') { pos--; goto check; } 2092 + else if (*pos == '\n') { pos++; goto end; } 2093 + else goto start; 2094 + 2095 + end: 2096 + code->cursor.position = pos; 2097 + updateColumn(code); 2098 + updateEditor(code); 2099 + } 2100 + 2101 + static void seekForward(Code* code, char sought) 2102 + { 2103 + char* start = code->cursor.position; 2104 + code->cursor.position++; 2105 + while( 2106 + *code->cursor.position != sought 2107 + && *code->cursor.position != '\n' 2108 + && *code->cursor.position != '\0' 2109 + ) 2110 + code->cursor.position++; 2111 + if (*code->cursor.position == '\n' || *code->cursor.position == '\0') 2112 + code->cursor.position = start; 2113 + 2114 + updateColumn(code); 2115 + updateEditor(code); 2116 + 2117 + } 2118 + static void seekBackward(Code* code, char sought) 2119 + { 2120 + char* start = code->cursor.position; 2121 + code->cursor.position--; 2122 + while( 2123 + code->cursor.position > code->src 2124 + && *code->cursor.position != sought 2125 + && *code->cursor.position != '\n' 2126 + ) 2127 + code->cursor.position--; 2128 + 2129 + if (code->cursor.position <= code->src || *code->cursor.position == '\n') 2130 + code->cursor.position = start; 2131 + 2132 + updateColumn(code); 2133 + updateEditor(code); 2134 + } 2135 + 2136 + static void findNextPopupText(Code* code) { 2137 + if (*code->popup.text) 2138 + { 2139 + char* pos = downStrStr(code->src, code->cursor.position, code->popup.text); 2140 + if (pos == code->cursor.position) 2141 + { 2142 + pos += strlen(code->popup.text); 2143 + pos = downStrStr(code->src, pos, code->popup.text); 2144 + } 2145 + if (pos == NULL) 2146 + pos = downStrStr(code->src, code->src, code->popup.text); 2147 + if (pos != NULL) 2148 + { 2149 + code->cursor.position = pos; 2150 + updateColumn(code); 2151 + } 2152 + } 2153 + } 2154 + 2155 + static bool processViPosition(Code* code, bool ctrl, bool alt, bool shift) 2156 + { 2157 + bool clear = !(shift || ctrl || alt); 2158 + 2159 + bool processed = true; 2160 + if (clear && keyWasPressed(code->studio, tic_key_k)) upLine(code); 2161 + else if (clear && keyWasPressed(code->studio, tic_key_j)) downLine(code); 2162 + else if (clear && keyWasPressed(code->studio, tic_key_h)) leftColumn(code); 2163 + else if (clear && keyWasPressed(code->studio, tic_key_l)) rightColumn(code); 2164 + 2165 + //no need to be elitist, arrow keys can work too 2166 + else if (keyWasPressed(code->studio, tic_key_up)) upLine(code); 2167 + else if (keyWasPressed(code->studio, tic_key_down)) downLine(code); 2168 + else if (keyWasPressed(code->studio, tic_key_left)) leftColumn(code); 2169 + else if (keyWasPressed(code->studio, tic_key_right)) rightColumn(code); 2170 + 2171 + else if (clear && keyWasPressed(code->studio, tic_key_g)) goCodeHome(code); 2172 + else if (shift && keyWasPressed(code->studio, tic_key_g)) goCodeEnd(code); 2173 + 2174 + else if (keyWasPressed(code->studio, tic_key_home)) goHome(code); 2175 + else if (clear && keyWasPressed(code->studio, tic_key_0)) goHome(code); 2176 + else if (keyWasPressed(code->studio, tic_key_end)) goEnd(code); 2177 + else if (shift && keyWasPressed(code->studio, tic_key_4)) goEnd(code); 2178 + 2179 + else if (keyWasPressed(code->studio, tic_key_pageup)) pageUp(code); 2180 + else if (ctrl && keyWasPressed(code->studio, tic_key_u)) pageUp(code); 2181 + else if (keyWasPressed(code->studio, tic_key_pagedown)) pageDown(code); 2182 + else if (ctrl && keyWasPressed(code->studio, tic_key_d)) pageDown(code); 2183 + 2184 + else if (clear && keyWasPressed(code->studio, tic_key_b)) leftWord(code); 2185 + else if (clear && keyWasPressed(code->studio, tic_key_w)) rightWord(code); 2186 + 2187 + else if (shift && keyWasPressed(code->studio, tic_key_6)) 2188 + { 2189 + goHome(code); 2190 + while (*code->cursor.position == ' ' || *code->cursor.position == '\t') 2191 + code->cursor.position++; 2192 + } 2193 + 2194 + else if (shift && keyWasPressed(code->studio, tic_key_j)) 2195 + halfPageDown(code); 2196 + 2197 + else if (shift && keyWasPressed(code->studio, tic_key_k)) 2198 + halfPageUp(code); 2199 + 2200 + else if (shift && keyWasPressed(code->studio, tic_key_leftbracket)) 2201 + seekEmptyLineBackward(code); 2202 + 2203 + else if (shift && keyWasPressed(code->studio, tic_key_rightbracket)) 2204 + seekEmptyLineForward(code); 2205 + 2206 + else if (shift && keyWasPressed(code->studio, tic_key_5)) 2207 + { 2208 + const char* pos = findMatchedDelim(code, code->cursor.position); 2209 + if (pos != NULL) 2210 + { 2211 + code->cursor.position = (char*) pos; 2212 + updateColumn(code); 2213 + updateEditor(code); 2214 + } 2215 + } 2216 + 2217 + else if (clear && keyWasPressed(code->studio, tic_key_f)) 2218 + setStudioViMode(code->studio, VI_SEEK); 2219 + 2220 + else if (shift && keyWasPressed(code->studio, tic_key_f)) 2221 + setStudioViMode(code->studio, VI_SEEK_BACK); 2222 + 2223 + else if(clear && keyWasPressed(code->studio, tic_key_semicolon)) 2224 + seekForward(code, *code->cursor.position); 2225 + 2226 + else if(shift && keyWasPressed(code->studio, tic_key_semicolon)) 2227 + seekBackward(code, *code->cursor.position); 2228 + 2229 + else processed = false; 2230 + 2231 + return processed; 2232 + } 2233 + 2234 + static void updateGotoCode(Code* code); 2235 + static void processViGoto(Code* code, s32 initial) 2236 + { 2237 + setCodeMode(code, TEXT_GOTO_MODE); 2238 + code->popup.text[0] = '0' + initial; 2239 + code->popup.text[1] = '\0'; 2240 + updateGotoCode(code); 2241 + } 2242 + 2243 + static char* findStringStart(Code* code, char* pos) { 2244 + char sentinel = *pos; 2245 + 2246 + char* target = pos; //we will scan to the given position 2247 + pos = getLineByPos(code, pos); //from the beginning of the line 2248 + char* start = NULL; 2249 + 2250 + //goto state machine! 2251 + start: 2252 + if(pos == target) goto end; 2253 + else if(*pos == '\\') { pos++; goto escape; } 2254 + else if (*pos == sentinel) 2255 + { 2256 + start=start?NULL:pos; 2257 + pos++; 2258 + goto start; 2259 + } 2260 + else { pos++; goto start; } 2261 + escape : 2262 + if (pos == target) goto end; 2263 + else { pos++; goto start; } 2264 + end: 2265 + return start; 2266 + } 2267 + 2268 + static char* findStringEnd(char* pos) { 2269 + char sentinel = *pos; //can handle single or double quotes 2270 + //or anything else I guess 2271 + if (*pos == '\0') goto end; 2272 + else pos++; //move past the sentinel so we don't immediately detect the end 2273 + 2274 + //goto state machine! 2275 + start: 2276 + if(*pos == '\0' || *pos == '\n' || *pos == sentinel) goto end; 2277 + else if(*pos == '\\') { pos++; goto escape; } 2278 + else { pos++; goto start; } 2279 + escape : 2280 + if (*pos == '\0' || *pos == '\n') goto end; 2281 + else { pos++; goto start; } 2282 + end: 2283 + return pos; 2284 + } 2285 + 2286 + 2287 + //pass in pointer to beginnign of word and its length 2288 + //so you can just use the word in src 2289 + static char* findFunctionDefinition(Code* code, char* name, size_t length) { 2290 + char* result = NULL; 2291 + 2292 + tic_mem* tic = code->tic; 2293 + const tic_script_config* config = tic_core_script_config(tic); 2294 + 2295 + if(config->getOutline) 2296 + { 2297 + s32 osize = 0; 2298 + const tic_outline_item* items = config->getOutline(code->src, &osize); 2299 + 2300 + if(items) 2301 + { 2302 + for(size_t i = 0; i < osize; i++) 2303 + { 2304 + const tic_outline_item* it = items + i; 2305 + 2306 + if(code->state[it->pos - code->src].syntax == SyntaxType_COMMENT) 2307 + continue; 2308 + if (strncmp(name, it->pos, length) == 0) 2309 + { 2310 + result = (char*) it->pos; 2311 + break; 2312 + } 2313 + } 2314 + } 2315 + } 2316 + 2317 + return result; 2318 + } 2319 + 2320 + 2321 + static void processViChange(Code* code) { 2322 + //if on a delimiter change the contents of the delimiter 2323 + if (matchingDelim(*code->cursor.position)) 2324 + { 2325 + const char* match = findMatchedDelim(code, code->cursor.position); 2326 + if (match == 0) 2327 + deleteChar(code); 2328 + else 2329 + { 2330 + if (code->cursor.position > match) 2331 + { 2332 + char* temp = code->cursor.position; 2333 + code->cursor.position = (char*) match; 2334 + match = temp; 2335 + } 2336 + deleteCode(code, code->cursor.position+1, (char*) match); 2337 + code->cursor.position++; 2338 + } 2339 + } 2340 + //if on a quotation seek to change within the quotation 2341 + else if(*code->cursor.position == '"' || *code->cursor.position == '\'') 2342 + { 2343 + char* start = findStringStart(code, code->cursor.position); 2344 + if (start == NULL) start = code->cursor.position; 2345 + char* end = findStringEnd(start); 2346 + start++; //advance one to leave the initial quote alone 2347 + deleteCode(code, start, end); 2348 + code->cursor.position = start; 2349 + } 2350 + else if(!isalnum_(code, *code->cursor.position)) 2351 + deleteChar(code); 2352 + else //change the word under the cursor 2353 + { 2354 + //only call left word if we are not already on the word border 2355 + if ( 2356 + code->cursor.position > code->src 2357 + && isalnum_(code, *(code->cursor.position-1)) 2358 + ) 2359 + leftWord(code); 2360 + deleteWord(code); 2361 + } 2362 + } 2363 + 2364 + static char toggleCase(char c) { 2365 + if (isupper(c)) 2366 + return tolower(c); 2367 + else if(islower(c)) 2368 + return toupper(c); 2369 + else 2370 + return c; 2371 + } 2372 + 2373 + static void processViKeyboard(Code* code) 2374 + { 2375 + 2376 + tic_mem* tic = code->tic; 2377 + bool shift = tic_api_key(tic, tic_key_shift); 2378 + bool ctrl = tic_api_key(tic, tic_key_ctrl); 2379 + bool alt = tic_api_key(tic, tic_key_alt); 2380 + bool clear = !(shift || ctrl || alt); 2381 + 2382 + ViMode mode = getStudioViMode(code->studio); 2383 + 2384 + //keep these the same to be consistent with the other editors 2385 + bool usedClipboard = true; 2386 + switch(getClipboardEvent(code->studio)) 2387 + { 2388 + case TIC_CLIPBOARD_CUT: cutToClipboard(code, false); break; 2389 + case TIC_CLIPBOARD_COPY: copyToClipboard(code, false); break; 2390 + case TIC_CLIPBOARD_PASTE: copyFromClipboard(code, false); break; 2391 + default: usedClipboard = false; break; 2392 + } 2393 + 2394 + if(usedClipboard) 2395 + { 2396 + if (mode != VI_INSERT) 2397 + setStudioViMode(code->studio, VI_NORMAL); 2398 + updateEditor(code); 2399 + return; 2400 + } 2401 + 2402 + 2403 + if (mode == VI_INSERT) 2404 + { 2405 + if (keyWasPressed(code->studio, tic_key_escape)) { 2406 + setStudioViMode(code->studio, VI_NORMAL); 2407 + history(code); //needs to come after the mode switch or won't be honored 2408 + } 2409 + 2410 + else if (keyWasPressed(code->studio, tic_key_backspace)) 2411 + backspaceChar(code); 2412 + 2413 + else if (keyWasPressed(code->studio, tic_key_tab)) 2414 + doTab(code, shift, ctrl); 2415 + 2416 + else if (keyWasPressed(code->studio, tic_key_return)) 2417 + newLine(code); 2418 + 2419 + else if (clear || shift) 2420 + { 2421 + char sym = getKeyboardText(code->studio); 2422 + if(sym) 2423 + { 2424 + inputSymbol(code, sym); 2425 + updateEditor(code); 2426 + } 2427 + } 2428 + } 2429 + else if(mode == VI_NORMAL) 2430 + { 2431 + bool processed = true; 2432 + 2433 + code->cursor.selection = NULL; 2434 + 2435 + if (processViPosition(code, ctrl, alt, shift)); 2436 + 2437 + else if (clear && keyWasPressed(code->studio, tic_key_i)) 2438 + setStudioViMode(code->studio, VI_INSERT); 2439 + 2440 + else if (clear && keyWasPressed(code->studio, tic_key_a)) 2441 + { 2442 + setStudioViMode(code->studio, VI_INSERT); 2443 + rightColumn(code); 2444 + } 2445 + else if (clear && keyWasPressed(code->studio, tic_key_o)) 2446 + { 2447 + setStudioViMode(code->studio, VI_INSERT); 2448 + goEnd(code); 2449 + newLine(code); 2450 + } 2451 + 2452 + else if (shift && keyWasPressed(code->studio, tic_key_o)) 2453 + { 2454 + setStudioViMode(code->studio, VI_INSERT); 2455 + goHome(code); 2456 + newLine(code); 2457 + upLine(code); 2458 + } 2459 + else if (clear && keyWasPressed(code->studio, tic_key_space)) 2460 + { 2461 + size_t col = code->cursor.column; 2462 + goEnd(code); 2463 + newLine(code); 2464 + code->cursor.column = col; 2465 + upLine(code); 2466 + } 2467 + else if (shift && keyWasPressed(code->studio, tic_key_space)) 2468 + { 2469 + size_t col = code->cursor.column; 2470 + goHome(code); 2471 + newLine(code); 2472 + code->cursor.position += col; 2473 + updateColumn(code); 2474 + } 2475 + 2476 + else if (clear && keyWasPressed(code->studio, tic_key_v)) 2477 + setStudioViMode(code->studio, VI_SELECT); 2478 + 2479 + else if (clear && keyWasPressed(code->studio, tic_key_slash)) 2480 + setCodeMode(code, TEXT_FIND_MODE); 2481 + 2482 + else if(clear && keyWasPressed(code->studio, tic_key_n)) 2483 + findNextPopupText(code); 2484 + 2485 + else if(shift && keyWasPressed(code->studio, tic_key_3)) 2486 + { 2487 + char* word_start = leftPos(code, code->cursor.position, isalnum_); 2488 + char* word_end = rightPos(code, code->cursor.position, isalnum_); 2489 + size_t size = word_end - word_start; 2490 + if (size+1 < STUDIO_TEXT_BUFFER_WIDTH) 2491 + { 2492 + memcpy(code->popup.text, word_start, size); 2493 + code->popup.text[size] = 0; 2494 + } 2495 + findNextPopupText(code); 2496 + } 2497 + else if(shift && keyWasPressed(code->studio, tic_key_n)) 2498 + { 2499 + if (*code->popup.text) 2500 + { 2501 + char* pos = upStrStr(code->src, code->cursor.position, code->popup.text); 2502 + if (pos == NULL) 2503 + pos = upStrStr(code->src, code->src+strlen(code->src), code->popup.text); 2504 + if (pos != NULL) 2505 + { 2506 + code->cursor.position = pos; 2507 + updateColumn(code); 2508 + } 2509 + } 2510 + } 2511 + 2512 + else if (clear && keyWasPressed(code->studio, tic_key_leftbracket)) 2513 + { 2514 + char* word_start = leftPos(code, code->cursor.position, isalnum_); 2515 + char* word_end = rightPos(code, code->cursor.position, isalnum_); 2516 + size_t size = word_end - word_start; 2517 + 2518 + char* def = findFunctionDefinition(code, word_start, size); 2519 + if (def != NULL) 2520 + { 2521 + code->cursor.position = def; 2522 + updateColumn(code); 2523 + } 2524 + 2525 + } 2526 + 2527 + else if (clear && keyWasPressed(code->studio, tic_key_r)) 2528 + setCodeMode(code, TEXT_REPLACE_MODE); 2529 + 2530 + else if (clear && keyWasPressed(code->studio, tic_key_u)) undo(code); 2531 + else if (shift && keyWasPressed(code->studio, tic_key_u)) redo(code); 2532 + 2533 + else if (clear && keyWasPressed(code->studio, tic_key_p)) 2534 + { 2535 + if (clipboardHasNewline()) 2536 + { 2537 + downLine(code); 2538 + goHome(code); 2539 + char* pos = code->cursor.position; 2540 + copyFromClipboard(code, false); 2541 + code->cursor.position = pos; 2542 + } else copyFromClipboard(code, false); 2543 + } 2544 + 2545 + else if (shift && keyWasPressed(code->studio, tic_key_p)) 2546 + { 2547 + if (clipboardHasNewline()) 2548 + { 2549 + goHome(code); 2550 + char* pos = code->cursor.position; 2551 + copyFromClipboard(code, false); 2552 + code->cursor.position = pos; 2553 + } else copyFromClipboard(code, false); 2554 + } 2555 + else if (alt && keyWasPressed(code->studio, tic_key_f)) 2556 + code->altFont = !code->altFont; 2557 + 2558 + else if (alt && keyWasPressed(code->studio, tic_key_s)) 2559 + code->shadowText = !code->shadowText; 2560 + 2561 + else if (clear && keyWasPressed(code->studio, tic_key_1)) processViGoto(code, 1); 2562 + else if (clear && keyWasPressed(code->studio, tic_key_2)) processViGoto(code, 2); 2563 + else if (clear && keyWasPressed(code->studio, tic_key_3)) processViGoto(code, 3); 2564 + else if (clear && keyWasPressed(code->studio, tic_key_4)) processViGoto(code, 4); 2565 + else if (clear && keyWasPressed(code->studio, tic_key_5)) processViGoto(code, 5); 2566 + else if (clear && keyWasPressed(code->studio, tic_key_6)) processViGoto(code, 6); 2567 + else if (clear && keyWasPressed(code->studio, tic_key_7)) processViGoto(code, 7); 2568 + else if (clear && keyWasPressed(code->studio, tic_key_8)) processViGoto(code, 8); 2569 + else if (clear && keyWasPressed(code->studio, tic_key_9)) processViGoto(code, 9); 2570 + 2571 + else if (shift && keyWasPressed(code->studio, tic_key_slash)) setCodeMode(code, TEXT_OUTLINE_MODE); 2572 + 2573 + else if (shift && keyWasPressed(code->studio, tic_key_m)) setCodeMode(code, TEXT_BOOKMARK_MODE); 2574 + else if (clear && keyWasPressed(code->studio, tic_key_m)) toggleBookmark(code, getLineByPos(code, code->cursor.position)); 2575 + else if (clear && keyWasPressed(code->studio, tic_key_comma)) 2576 + { 2577 + if(!goPrevBookmark(code, getPrevLineByPos(code, code->cursor.position))) 2578 + goPrevBookmark(code, code->src + strlen(code->src)); 2579 + } 2580 + else if (clear && keyWasPressed(code->studio, tic_key_period)) 2581 + { 2582 + if(!goNextBookmark(code, getNextLineByPos(code, code->cursor.position))) 2583 + goNextBookmark(code, code->src); 2584 + } 2585 + 2586 + else if (clear && keyWasPressed(code->studio, tic_key_z)) 2587 + recenterScroll(code, true); //use emacs mode because it is nice 2588 + 2589 + else if (clear && keyWasPressed(code->studio, tic_key_minus)) 2590 + commentLine(code); 2591 + 2592 + else if (clear && keyWasPressed(code->studio, tic_key_x)) 2593 + deleteChar(code); 2594 + 2595 + else if (shift && keyWasPressed(code->studio, tic_key_grave)) 2596 + { 2597 + *code->cursor.position = toggleCase(*code->cursor.position); 2598 + history(code); 2599 + } 2600 + 2601 + else if (clear && keyWasPressed(code->studio, tic_key_d)) 2602 + cutToClipboard(code, false); //it seems like if there is not selection it will act on the current line by default, how nice 2603 + else if (clear && keyWasPressed(code->studio, tic_key_y)) 2604 + copyToClipboard(code, false); 2605 + 2606 + else if (shift && keyWasPressed(code->studio, tic_key_w)) 2607 + saveProject(code->studio); 2608 + else if (shift && keyWasPressed(code->studio, tic_key_r)) 2609 + runGame(code->studio); 2610 + 2611 + else if (clear && keyWasPressed(code->studio, tic_key_c)) 2612 + { 2613 + setStudioViMode(code->studio, VI_INSERT); 2614 + processViChange(code); 2615 + } 2616 + 2617 + else if (shift && keyWasPressed(code->studio, tic_key_c)) 2618 + { 2619 + setStudioViMode(code->studio, VI_INSERT); 2620 + char* start = code->cursor.position; 2621 + goEnd(code); 2622 + deleteCode(code, start, code->cursor.position); 2623 + code->cursor.position = start; 2624 + } 2625 + 2626 + else if (shift && keyWasPressed(code->studio, tic_key_comma)) 2627 + doTab(code, true, false); 2628 + else if (shift && keyWasPressed(code->studio, tic_key_period)) 2629 + doTab(code, false, true); 2630 + 2631 + else processed = false; 2632 + 2633 + if (processed) updateEditor(code); 2634 + } 2635 + else if (mode == VI_SELECT) { 2636 + if (code->cursor.selection == NULL) 2637 + code->cursor.selection = code->cursor.position; 2638 + 2639 + bool processed = true; 2640 + 2641 + if (processViPosition(code, ctrl, alt, shift)); 2642 + 2643 + else if (keyWasPressed(code->studio, tic_key_escape)) 2644 + setStudioViMode(code->studio, VI_NORMAL); 2645 + 2646 + else if (clear && keyWasPressed(code->studio, tic_key_minus)) 2647 + { 2648 + commentLine(code); 2649 + setStudioViMode(code->studio, VI_NORMAL); 2650 + } 2651 + 2652 + else if (clear && keyWasPressed(code->studio, tic_key_y)) 2653 + { 2654 + copyToClipboard(code, false); 2655 + setStudioViMode(code->studio, VI_NORMAL); 2656 + } 2657 + else if (clear && keyWasPressed(code->studio, tic_key_d)) 2658 + { 2659 + cutToClipboard(code, false); 2660 + setStudioViMode(code->studio, VI_NORMAL); 2661 + } 2662 + else if (clear && keyWasPressed(code->studio, tic_key_p)) 2663 + { 2664 + copyFromClipboard(code, false); 2665 + setStudioViMode(code->studio, VI_NORMAL); 2666 + 2667 + } else if (clear && keyWasPressed(code->studio, tic_key_c)) 2668 + { 2669 + setStudioViMode(code->studio, VI_INSERT); 2670 + if (code->cursor.selection != NULL) 2671 + deleteCode(code, code->cursor.selection, code->cursor.position); 2672 + code->cursor.position = code->cursor.selection; 2673 + code->cursor.selection = NULL; 2674 + } 2675 + 2676 + else if (shift && keyWasPressed(code->studio, tic_key_comma)) 2677 + doTab(code, true, false); 2678 + else if (shift && keyWasPressed(code->studio, tic_key_period)) 2679 + doTab(code, false, true); 2680 + 2681 + else if (clear && keyWasPressed(code->studio, tic_key_slash)) 2682 + { 2683 + setStudioViMode(code->studio, VI_NORMAL); 2684 + setCodeMode(code, TEXT_FIND_MODE); 2685 + } 2686 + 2687 + else if (clear && keyWasPressed(code->studio, tic_key_r)) 2688 + { 2689 + setStudioViMode(code->studio, VI_NORMAL); 2690 + setCodeMode(code, TEXT_REPLACE_MODE); 2691 + } 2692 + 2693 + else if (shift && keyWasPressed(code->studio, tic_key_grave)) 2694 + { 2695 + for(char* i = code->cursor.selection ;i != code->cursor.position; i++) 2696 + *i = toggleCase(*i); 2697 + history(code); 2698 + } 2699 + 2700 + else processed = false; 2701 + 2702 + if (processed) updateEditor(code); 2703 + 2704 + } 2705 + else if (mode == VI_SEEK) 2706 + { 2707 + 2708 + if (keyWasPressed(code->studio, tic_key_escape)) 2709 + setStudioViMode(code->studio, VI_NORMAL); 2710 + 2711 + else if (clear || shift) { 2712 + char sym = getKeyboardText(code->studio); 2713 + if(sym) 2714 + { 2715 + seekForward(code, sym); 2716 + if (code->cursor.selection == NULL) 2717 + setStudioViMode(code->studio, VI_NORMAL); 2718 + else 2719 + setStudioViMode(code->studio, VI_SELECT); 2720 + } 2721 + } 2722 + } 2723 + else if (mode == VI_SEEK_BACK) 2724 + { 2725 + 2726 + if (keyWasPressed(code->studio, tic_key_escape)) 2727 + setStudioViMode(code->studio, VI_NORMAL); 2728 + 2729 + else if (clear || shift) { 2730 + char sym = getKeyboardText(code->studio); 2731 + if(sym) 2732 + { 2733 + seekBackward(code, sym); 2734 + if (code->cursor.selection == NULL) 2735 + setStudioViMode(code->studio, VI_NORMAL); 2736 + else 2737 + setStudioViMode(code->studio, VI_SELECT); 2738 + } 2739 + } 2740 + } 2741 + } 2742 + 1945 2743 static void processKeyboard(Code* code) 1946 2744 { 1947 2745 tic_mem* tic = code->tic; 1948 2746 1949 2747 if(tic->ram->input.keyboard.data == 0) return; 1950 2748 1951 - const bool emacsMode = getConfig(code->studio)->options.emacsMode; 2749 + enum KeybindMode keymode = getConfig(code->studio)->options.keybindMode; 2750 + 2751 + if (keymode == KEYBIND_VI) 2752 + { 2753 + processViKeyboard(code); 2754 + return; 2755 + } 2756 + 2757 + const bool emacsMode = keymode == KEYBIND_EMACS; 1952 2758 1953 2759 if (!emacsMode) 1954 2760 { ··· 2103 2909 } 2104 2910 2105 2911 if(changedSelection || usedKeybinding) updateEditor(code); 2912 + else 2913 + { 2914 + char sym = getKeyboardText(code->studio); 2915 + if(sym) 2916 + { 2917 + inputSymbol(code, sym); 2918 + updateEditor(code); 2919 + } 2920 + } 2921 + 2106 2922 } 2107 2923 2108 2924 static void processMouse(Code* code) ··· 2215 3031 } 2216 3032 2217 3033 processKeyboard(code); 2218 - 2219 - if(!tic_api_key(tic, tic_key_ctrl) && !tic_api_key(tic, tic_key_alt)) 2220 - { 2221 - char sym = getKeyboardText(code->studio); 2222 - 2223 - if(sym) 2224 - { 2225 - inputSymbol(code, sym); 2226 - updateEditor(code); 2227 - } 2228 - } 2229 - 2230 3034 processMouse(code); 2231 3035 2232 3036 tic_api_cls(code->tic, getConfig(code->studio)->theme.code.BG); ··· 2267 3071 code->cursor.selection = pos + strlen(code->popup.text); 2268 3072 2269 3073 centerScroll(code); 3074 + updateColumn(code); 2270 3075 updateEditor(code); 2271 3076 } 2272 3077 } 2273 3078 2274 - static char* upStrStr(const char* start, const char* from, const char* substr) 3079 + static void textFindTick(Code* code) 2275 3080 { 2276 - const char* ptr = from-1; 2277 - size_t len = strlen(substr); 2278 3081 2279 - if(len > 0) 2280 - { 2281 - while(ptr >= start) 2282 - { 2283 - if(memcmp(ptr, substr, len) == 0) 2284 - return (char*)ptr; 2285 3082 2286 - ptr--; 2287 - } 2288 - } 2289 - 2290 - return NULL; 2291 - } 2292 - 2293 - static char* downStrStr(const char* start, const char* from, const char* substr) 2294 - { 2295 - return strstr(from, substr); 2296 - } 2297 - 2298 - static void textFindTick(Code* code) 2299 - { 2300 3083 if(keyWasPressed(code->studio, tic_key_return)) setCodeMode(code, TEXT_EDIT_MODE); 2301 3084 else if(keyWasPressed(code->studio, tic_key_up) 2302 3085 || keyWasPressed(code->studio, tic_key_down) ··· 2322 3105 } 2323 3106 2324 3107 char sym = getKeyboardText(code->studio); 2325 - 2326 3108 if(sym) 2327 3109 { 2328 3110 if(strlen(code->popup.text) + 1 < sizeof code->popup.text) ··· 2337 3119 2338 3120 drawCode(code, false); 2339 3121 drawPopupBar(code, "FIND:"); 3122 + drawStatus(code); 3123 + } 3124 + 3125 + static void textReplaceTick(Code* code) 3126 + { 3127 + 3128 + if(keyWasPressed(code->studio, tic_key_return)) { 3129 + if (*code->popup.text && code->popup.offset == NULL) //still in "find" mode 3130 + { 3131 + code->popup.offset = code->popup.text + strlen(code->popup.text); 3132 + strcat(code->popup.text, " WITH:"); 3133 + } 3134 + else if(*code->popup.text) 3135 + { 3136 + *code->popup.offset = 0; 3137 + code->popup.offset += strlen(" WITH:"); 3138 + //execute the replace 3139 + 3140 + //if we have a selection only replace within the selection 3141 + char* start = code->src; 3142 + if (code->cursor.selection != NULL) 3143 + start = code->cursor.selection; 3144 + 3145 + char* pos = downStrStr(start, start, code->popup.text); 3146 + size_t src_length = strlen(code->src); 3147 + while(pos != NULL) 3148 + { 3149 + deleteCode(code, pos, pos+strlen(code->popup.text)); 3150 + insertCode(code, pos, code->popup.offset); 3151 + pos += strlen(code->popup.offset); 3152 + if (pos - code->src > src_length) pos = code->src + src_length; 3153 + 3154 + pos = downStrStr(code->src, pos, code->popup.text); 3155 + if (code->cursor.selection != NULL && pos > code->cursor.position) 3156 + break; 3157 + } 3158 + history(code); 3159 + updateEditor(code); 3160 + parseSyntaxColor(code); 3161 + setCodeMode(code, TEXT_EDIT_MODE); 3162 + } 3163 + } 3164 + 3165 + else if(keyWasPressed(code->studio, tic_key_backspace)) 3166 + { 3167 + if(*code->popup.text && code->popup.offset == NULL) 3168 + { 3169 + code->popup.text[strlen(code->popup.text)-1] = '\0'; 3170 + } 3171 + else if (*code->popup.text) 3172 + { 3173 + if (strlen(code->popup.offset) - strlen(" WITH:") > 0) 3174 + code->popup.text[strlen(code->popup.text)-1] = '\0'; 3175 + } 3176 + 3177 + } 3178 + 3179 + char sym = getKeyboardText(code->studio); 3180 + if(sym) 3181 + { 3182 + if(strlen(code->popup.text) + 1 < sizeof code->popup.text) 3183 + { 3184 + char str[] = {sym , 0}; 3185 + strcat(code->popup.text, str); 3186 + } 3187 + } 3188 + 3189 + tic_api_cls(code->tic, getConfig(code->studio)->theme.code.BG); 3190 + 3191 + drawCode(code, false); 3192 + drawPopupBar(code, "REPL:"); 2340 3193 drawStatus(code); 2341 3194 } 2342 3195 ··· 2698 3551 case TEXT_DRAG_CODE: textDragTick(code); break; 2699 3552 case TEXT_EDIT_MODE: textEditTick(code); break; 2700 3553 case TEXT_FIND_MODE: textFindTick(code); break; 3554 + case TEXT_REPLACE_MODE: textReplaceTick(code); break; 2701 3555 case TEXT_GOTO_MODE: textGoToTick(code); break; 2702 3556 case TEXT_BOOKMARK_MODE:textBookmarkTick(code); break; 2703 3557 case TEXT_OUTLINE_MODE: textOutlineTick(code); break; ··· 2716 3570 break; 2717 3571 case TEXT_DRAG_CODE: 2718 3572 setCodeMode(code, TEXT_EDIT_MODE); 2719 - break; 3573 + break; 2720 3574 default: 2721 3575 code->anim.movie = resetMovie(&code->anim.hide); 2722 3576
+2
src/studio/editors/code.h
··· 88 88 TEXT_GOTO_MODE, 89 89 TEXT_BOOKMARK_MODE, 90 90 TEXT_OUTLINE_MODE, 91 + TEXT_REPLACE_MODE, 91 92 TEXT_EDIT_MODE, 92 93 } mode; 93 94 94 95 struct 95 96 { 96 97 char text[STUDIO_TEXT_BUFFER_WIDTH - sizeof "FIND:"]; 98 + char* offset; 97 99 98 100 char* prevPos; 99 101 char* prevSel;
+19 -19
src/studio/screens/mainmenu.c
··· 196 196 197 197 #if defined(BUILD_EDITORS) 198 198 199 - static s32 optionEmacsModeGet(void* data) 199 + static s32 optionKeybindModeGet(void* data) 200 200 { 201 201 StudioMainMenu* main = data; 202 - return main->options->emacsMode ? 1 : 0; 202 + return main->options->keybindMode; 203 203 } 204 204 205 - static void optionEmacsModeSet(void* data, s32 pos) 205 + static void optionKeybindModeSet(void* data, s32 pos) 206 206 { 207 207 StudioMainMenu* main = data; 208 - main->options->emacsMode = pos == 1; 208 + main->options->keybindMode = (enum KeybindMode) pos; 209 209 } 210 210 211 - static MenuOption EmacsModeOption = 211 + static MenuOption KeybindModeOption = 212 212 { 213 - OPTION_VALUES({OffValue, OnValue}), 214 - optionEmacsModeGet, 215 - optionEmacsModeSet, 213 + OPTION_VALUES({"STANDARD", "EMACS", "VI"}), 214 + optionKeybindModeGet, 215 + optionKeybindModeSet, 216 216 }; 217 217 218 218 static s32 optionDevModeGet(void* data) ··· 234 234 optionDevModeSet, 235 235 }; 236 236 237 - static void showCodeEditorMenu(void* data, s32 pos); 237 + static void showEditorMenu(void* data, s32 pos); 238 238 239 239 #endif 240 240 ··· 260 260 OptionsMenu_IntegerScaleOption, 261 261 OptionsMenu_VolumeOption, 262 262 #if defined(BUILD_EDITORS) 263 - OptionsMenu_CodeEditor, 263 + OptionsMenu_Editor, 264 264 #endif 265 265 OptionsMenu_Gamepad, 266 266 OptionsMenu_Separator, ··· 280 280 {"INTEGER SCALE", NULL, &IntegerScaleOption}, 281 281 {"VOLUME", NULL, &VolumeOption}, 282 282 #if defined(BUILD_EDITORS) 283 - {"CODE EDITOR OPTIONS", showCodeEditorMenu}, 283 + {"EDITOR OPTIONS", showEditorMenu}, 284 284 #endif 285 285 {"SETUP GAMEPAD", showGamepadMenu}, 286 286 {""}, ··· 300 300 301 301 enum 302 302 { 303 - CodeEditorMenu_EmacsMode, 304 - CodeEditorMenu_Separator, 305 - CodeEditorMenu_Back, 303 + EditorMenu_KeybindMode, 304 + EditorMenu_Separator, 305 + EditorMenu_Back, 306 306 }; 307 307 308 - static const MenuItem CodeEditorMenu[] = 308 + static const MenuItem EditorMenu[] = 309 309 { 310 - {"EMACS MODE", NULL, &EmacsModeOption, "For the cool kids only"}, 310 + {"KEYBIND MODE", NULL, &KeybindModeOption, "For the cool kids only"}, 311 311 {""}, 312 312 {"BACK", showOptionsMenu, .back = true}, 313 313 }; 314 314 315 - static void showCodeEditorMenu(void* data, s32 pos) 315 + static void showEditorMenu(void* data, s32 pos) 316 316 { 317 317 StudioMainMenu* main = data; 318 318 319 - studio_menu_init(main->menu, CodeEditorMenu, 320 - COUNT_OF(CodeEditorMenu), CodeEditorMenu_EmacsMode, OptionsMenu_CodeEditor, showOptionsMenu, main); 319 + studio_menu_init(main->menu, EditorMenu, 320 + COUNT_OF(EditorMenu), EditorMenu_KeybindMode, OptionsMenu_Editor, showOptionsMenu, main); 321 321 } 322 322 #endif 323 323
+29 -1
src/studio/studio.c
··· 124 124 125 125 #if defined(BUILD_EDITORS) 126 126 EditorMode menuMode; 127 + ViMode viMode; 127 128 128 129 struct 129 130 { ··· 1247 1248 music->tab = (music->tab + 1) % MUSIC_TAB_COUNT; 1248 1249 } 1249 1250 #endif 1251 + 1252 + #if defined(BUILD_EDITORS) 1253 + studio->viMode = 0; 1254 + #endif 1250 1255 } 1251 1256 1252 1257 EditorMode getStudioMode(Studio* studio) ··· 1274 1279 studio->mode = TIC_RUN_MODE; 1275 1280 } 1276 1281 1282 + #if defined(BUILD_EDITORS) 1283 + void setStudioViMode(Studio* studio, ViMode mode) { 1284 + studio->viMode = mode; 1285 + } 1286 + 1287 + ViMode getStudioViMode(Studio* studio) { 1288 + return studio->viMode; 1289 + } 1290 + 1291 + bool checkStudioViMode(Studio* studio, ViMode mode) { 1292 + return ( 1293 + getConfig(studio)->options.keybindMode == KEYBIND_VI 1294 + && getStudioViMode(studio) == mode 1295 + ); 1296 + } 1297 + #endif 1298 + 1277 1299 static inline bool pointInRect(const tic_point* pt, const tic_rect* rect) 1278 1300 { 1279 1301 return (pt->x >= rect->x) ··· 1530 1552 } 1531 1553 1532 1554 #if defined(BUILD_EDITORS) 1533 - static void saveProject(Studio* studio) 1555 + void saveProject(Studio* studio) 1534 1556 { 1535 1557 CartSaveResult rom = studio->console->save(studio->console); 1536 1558 ··· 1753 1775 #if defined(BUILD_EDITORS) 1754 1776 else if(keyWasPressedOnce(studio, tic_key_escape)) 1755 1777 { 1778 + if( 1779 + getConfig(studio)->options.keybindMode == KEYBIND_VI 1780 + && getStudioViMode(studio) != VI_NORMAL 1781 + ) 1782 + return; 1783 + 1756 1784 switch(studio->mode) 1757 1785 { 1758 1786 case TIC_MENU_MODE:
+14
src/studio/studio.h
··· 113 113 TIC_MODES_COUNT 114 114 } EditorMode; 115 115 116 + typedef enum 117 + { 118 + VI_NORMAL, 119 + VI_INSERT, 120 + VI_SELECT, 121 + VI_SEEK, 122 + VI_SEEK_BACK, 123 + } ViMode; 124 + 116 125 enum 117 126 { 118 127 tic_icon_cut = 80, ··· 194 203 EditorMode getStudioMode(Studio* studio); 195 204 void exitStudio(Studio* studio); 196 205 206 + void setStudioViMode(Studio* studio, ViMode mode); 207 + ViMode getStudioViMode(Studio* studio); 208 + bool checkStudioViMode(Studio* studio, ViMode mode); 209 + 197 210 void toClipboard(const void* data, s32 size, bool flip); 198 211 bool fromClipboard(void* data, s32 size, bool flip, bool remove_white_spaces, bool sameSize); 199 212 ··· 236 249 void runGame(Studio* studio); 237 250 void exitGame(Studio* studio); 238 251 void resumeGame(Studio* studio); 252 + void saveProject(Studio* studio); 239 253 240 254 tic_tiles* getBankTiles(Studio* studio); 241 255 tic_palette* getBankPalette(Studio* studio, bool bank);
+7 -1
src/studio/system.h
··· 73 73 macro(COMMENT) \ 74 74 macro(SIGN) 75 75 76 + enum KeybindMode { 77 + KEYBIND_STANDARD, 78 + KEYBIND_EMACS, 79 + KEYBIND_VI 80 + }; 81 + 76 82 typedef struct 77 83 { 78 84 struct ··· 130 136 s32 volume; 131 137 tic_mapping mapping; 132 138 #if defined(BUILD_EDITORS) 133 - bool emacsMode; 139 + enum KeybindMode keybindMode; 134 140 bool devmode; 135 141 #endif 136 142 } options;