diff options
author | Kartik K. Agaram <vc@akkartik.com> | 2015-05-30 11:38:16 -0700 |
---|---|---|
committer | Kartik K. Agaram <vc@akkartik.com> | 2015-05-30 12:02:29 -0700 |
commit | 3d68a0b026e6551e962124f3a1831120dbd553b7 (patch) | |
tree | 6a19bebe955a00eded4a51435fa1e6d584c3c983 | |
parent | 76acf2b00e5fb265f1b64b2194367d2848afe400 (diff) | |
download | mu-3d68a0b026e6551e962124f3a1831120dbd553b7.tar.gz |
1514 - cleaner way to show backspaces in fake keyboard
In the process we now support unicode in all mu strings!
-rw-r--r-- | 042new.cc | 41 | ||||
-rw-r--r-- | 072scenario_screen.cc | 4 | ||||
-rw-r--r-- | 075scenario_keyboard.cc | 25 | ||||
-rw-r--r-- | repl.mu | 66 |
4 files changed, 76 insertions, 60 deletions
diff --git a/042new.cc b/042new.cc index d476a5c5..facb9420 100644 --- a/042new.cc +++ b/042new.cc @@ -159,7 +159,7 @@ recipe main [ +new: routine allocated memory from 1000 to 1002 +new: routine allocated memory from 1002 to 1004 -//:: Next, extend 'new' to handle a string literal argument. +//:: Next, extend 'new' to handle a unicode string literal argument. :(scenario new_string) recipe main [ @@ -169,6 +169,16 @@ recipe main [ # number code for 'e' +mem: storing 101 in location 2 +:(scenario new_string_handles_unicode) +recipe main [ + 1:address:array:character <- new [a«c] + 2:number <- length 1:address:array:character/deref + 3:character <- index 1:address:array:character/deref, 1:literal +] ++mem: storing 3 in location 2 +# unicode for '«' ++mem: storing 171 in location 3 + :(before "End NEW Transform Special-cases") if (inst.ingredients.at(0).properties.at(0).second.at(0) == "literal-string") { // skip transform @@ -180,7 +190,7 @@ recipe main [ if (isa_literal(current_instruction().ingredients.at(0)) && current_instruction().ingredients.at(0).properties.at(0).second.at(0) == "literal-string") { // allocate an array just large enough for it - long long int string_length = SIZE(current_instruction().ingredients.at(0).name); + long long int string_length = unicode_length(current_instruction().ingredients.at(0).name); //? cout << "string_length is " << string_length << '\n'; //? 1 ensure_space(string_length+1); // don't forget the extra location for array size products.resize(1); @@ -188,8 +198,16 @@ if (isa_literal(current_instruction().ingredients.at(0)) // initialize string //? cout << "new string literal: " << current_instruction().ingredients.at(0).name << '\n'; //? 1 Memory[Current_routine->alloc++] = string_length; + long long int curr = 0; + const string& contents = current_instruction().ingredients.at(0).name; + const char* raw_contents = contents.c_str(); for (long long int i = 0; i < string_length; ++i) { - Memory[Current_routine->alloc++] = current_instruction().ingredients.at(0).name.at(i); + uint32_t curr_character; + assert(curr < SIZE(contents)); + tb_utf8_char_to_unicode(&curr_character, &raw_contents[curr]); + Memory[Current_routine->alloc] = curr_character; + curr += tb_utf8_char_length(raw_contents[curr]); + ++Current_routine->alloc; } // mu strings are not null-terminated in memory break; @@ -204,3 +222,20 @@ recipe main [ ] +new: routine allocated memory from 1000 to 1002 +new: routine allocated memory from 1002 to 1004 + +//: helpers +:(code) +long long int unicode_length(const string& s) { + const char* in = s.c_str(); + long long int result = 0; + long long int curr = 0; + while (curr < SIZE(s)) { // carefully bounds-check on the string + // before accessing its raw pointer + ++result; + curr += tb_utf8_char_length(in[curr]); + } + return result; +} + +:(before "End Includes") +#include"termbox/termbox.h" // for unicode primitives diff --git a/072scenario_screen.cc b/072scenario_screen.cc index 7c5de630..29810906 100644 --- a/072scenario_screen.cc +++ b/072scenario_screen.cc @@ -1,7 +1,8 @@ //: Clean syntax to manipulate and check the screen in scenarios. //: Instructions 'assume-screen' and 'screen-should-contain' implicitly create //: a variable called 'screen' that is accessible inside other 'run' -//: instructions in the scenario. +//: instructions in the scenario. 'screen-should-contain' can check unicode +//: characters in the fake screen :(scenarios run_mu_scenario) :(scenario screen_in_scenario) @@ -21,7 +22,6 @@ scenario screen-in-scenario [ ] :(scenario screen_in_scenario_unicode) -# screen-should-contain can check unicode characters in the fake screen scenario screen-in-scenario-unicode-color [ assume-screen 5:literal/width, 3:literal/height run [ diff --git a/075scenario_keyboard.cc b/075scenario_keyboard.cc index 363b3afd..bb0d478b 100644 --- a/075scenario_keyboard.cc +++ b/075scenario_keyboard.cc @@ -1,7 +1,8 @@ //: Clean syntax to manipulate and check the keyboard in scenarios. //: Instruction 'assume-keyboard' implicitly creates a variable called //: 'keyboard' that is accessible inside other 'run' instructions in the -//: scenario. +//: scenario. Like with the fake screen, 'assume-keyboard' transparently +//: supports unicode. :(scenarios run_mu_scenario) :(scenario keyboard_in_scenario) @@ -58,3 +59,25 @@ if (curr.name == "assume-keyboard") { curr.products.push_back(reagent("keyboard:address")); curr.products.at(0).set_value(KEYBOARD); } + +//: Since we don't yet have a clean way to represent characters like backspace +//: in literal strings we can't easily pretend they were typed into the fake +//: keyboard. So we'll use special unicode characters in the literal and then +//: manually replace them with backspace. +:(before "End Primitive Recipe Declarations") +REPLACE_IN_KEYBOARD, +:(before "End Primitive Recipe Numbers") +Recipe_number["replace-in-keyboard"] = REPLACE_IN_KEYBOARD; +:(before "End Primitive Recipe Implementations") +case REPLACE_IN_KEYBOARD: { + long long int size = Memory[KEYBOARD]; + assert(scalar(ingredients.at(0))); + assert(scalar(ingredients.at(1))); + for (long long int curr = KEYBOARD+1; curr <= KEYBOARD+size; ++curr) { + if (Memory[curr] == ingredients.at(0).at(0)) { +//? cerr << "replacing\n"; //? 1 + Memory[curr] = ingredients.at(1).at(0); + } + } + break; +} diff --git a/repl.mu b/repl.mu index 1e95e7bf..c6165750 100644 --- a/repl.mu +++ b/repl.mu @@ -303,16 +303,9 @@ scenario read-instruction-color-comment [ scenario read-instruction-cancel-comment-on-backspace [ assume-screen 30:literal/width, 5:literal/height - assume-keyboard [#a<<z + assume-keyboard [#a««z ] - # setup: replace '<'s with backspace key since we can't represent backspace in strings - run [ - buf:address:array:character <- get keyboard:address:keyboard/deref, data:offset - first:address:character <- index-address buf:address:array:character/deref, 2:literal - first:address:character/deref <- copy 8:literal/backspace - second:address:character <- index-address buf:address:array:character/deref, 3:literal - second:address:character/deref <- copy 8:literal/backspace - ] + replace-in-keyboard 171:literal/«, 8:literal/backspace run [ read-instruction keyboard:address, screen:address ] @@ -328,18 +321,9 @@ scenario read-instruction-cancel-comment-on-backspace [ scenario read-instruction-cancel-comment-on-backspace2 [ assume-screen 30:literal/width, 5:literal/height - assume-keyboard [#ab<<<z + assume-keyboard [#ab«««z ] - # setup: replace '<'s with backspace key since we can't represent backspace in strings - run [ - buf:address:array:character <- get keyboard:address:keyboard/deref, data:offset - first:address:character <- index-address buf:address:array:character/deref, 3:literal - first:address:character/deref <- copy 8:literal/backspace - second:address:character <- index-address buf:address:array:character/deref, 4:literal - second:address:character/deref <- copy 8:literal/backspace - third:address:character <- index-address buf:address:array:character/deref, 5:literal - third:address:character/deref <- copy 8:literal/backspace - ] + replace-in-keyboard 171:literal/«, 8:literal/backspace run [ read-instruction keyboard:address, screen:address ] @@ -355,14 +339,9 @@ scenario read-instruction-cancel-comment-on-backspace2 [ scenario read-instruction-cancel-comment-on-backspace3 [ assume-screen 30:literal/width, 5:literal/height - assume-keyboard [#a<z + assume-keyboard [#a«z ] - # setup: replace '<'s with backspace key since we can't represent backspace in strings - run [ - buf:address:array:character <- get keyboard:address:keyboard/deref, data:offset - first:address:character <- index-address buf:address:array:character/deref, 2:literal - first:address:character/deref <- copy 8:literal/backspace - ] + replace-in-keyboard 171:literal/«, 8:literal/backspace run [ read-instruction keyboard:address, screen:address ] @@ -525,16 +504,9 @@ scenario read-instruction-color-string-inside-string [ scenario read-instruction-cancel-string-on-backspace [ assume-screen 30:literal/width, 5:literal/height # need to escape the '[' once for 'scenario' and once for 'assume-keyboard' - assume-keyboard [\\\[a<<z + assume-keyboard [\\\[a««z ] - # setup: replace '<'s with backspace key since we can't represent backspace in strings - run [ - buf:address:array:character <- get keyboard:address:keyboard/deref, data:offset - first-backspace:address:character <- index-address buf:address:array:character/deref, 2:literal - first-backspace:address:character/deref <- copy 8:literal/backspace - second-backspace:address:character <- index-address buf:address:array:character/deref, 3:literal - second-backspace:address:character/deref <- copy 8:literal/backspace - ] + replace-in-keyboard 171:literal/«, 8:literal/backspace run [ read-instruction keyboard:address, screen:address ] @@ -550,18 +522,9 @@ scenario read-instruction-cancel-string-on-backspace [ scenario read-instruction-cancel-string-inside-string-on-backspace [ assume-screen 30:literal/width, 5:literal/height - assume-keyboard [[a[b]<<<b] + assume-keyboard [\[a\[b\]«««b\] ] - # setup: replace '<'s with backspace key since we can't represent backspace in strings - run [ - buf:address:array:character <- get keyboard:address:keyboard/deref, data:offset - first-backspace:address:character <- index-address buf:address:array:character/deref, 5:literal - first-backspace:address:character/deref <- copy 8:literal/backspace - second-backspace:address:character <- index-address buf:address:array:character/deref, 6:literal - second-backspace:address:character/deref <- copy 8:literal/backspace - third-backspace:address:character <- index-address buf:address:array:character/deref, 7:literal - third-backspace:address:character/deref <- copy 8:literal/backspace - ] + replace-in-keyboard 171:literal/«, 8:literal/backspace run [ read-instruction keyboard:address, screen:address ] @@ -578,14 +541,9 @@ scenario read-instruction-cancel-string-inside-string-on-backspace [ scenario read-instruction-backspace-back-into-string [ assume-screen 30:literal/width, 5:literal/height # need to escape the '[' once for 'scenario' and once for 'assume-keyboard' - assume-keyboard [[a]<b + assume-keyboard [[a]«b ] - # setup: replace '<'s with backspace key since we can't represent backspace in strings - run [ - buf:address:array:character <- get keyboard:address:keyboard/deref, data:offset - first-backspace:address:character <- index-address buf:address:array:character/deref, 3:literal - first-backspace:address:character/deref <- copy 8:literal/backspace - ] + replace-in-keyboard 171:literal/«, 8:literal/backspace run [ read-instruction keyboard:address, screen:address ] |