//: 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 to later instructions in the //: scenario. 'screen-should-contain' can check unicode characters in the fake //: screen //: first make sure we don't mangle these instructions in other transforms :(before "End initialize_transform_rewrite_literal_string_to_text()") recipes_taking_literal_strings.insert("screen-should-contain"); recipes_taking_literal_strings.insert("screen-should-contain-in-color"); :(scenarios run_mu_scenario) :(scenario screen_in_scenario) scenario screen-in-scenario [ local-scope assume-screen 5/width, 3/height run [ a:char <- copy 97/a screen:&:screen <- print screen:&:screen, a ] screen-should-contain [ # 01234 .a . . . . . ] ] # checks are inside scenario :(scenario screen_in_scenario_unicode) # screen-should-contain can check unicode characters in the fake screen scenario screen-in-scenario-unicode [ local-scope assume-screen 5/width, 3/height run [ lambda:char <- copy 955/greek-small-lambda screen:&:screen <- print screen:&:screen, lambda a:char <- copy 97/a screen:&:screen <- print screen:&:screen, a ] screen-should-contain [ # 01234 .λa . . . . . ] ] # checks are inside scenario :(scenario screen_in_scenario_color) scenario screen-in-scenario-color [ local-scope assume-screen 5/width, 3/height run [ lambda:char <- copy 955/greek-small-lambda screen:&:screen <- print screen:&:screen, lambda, 1/red a:char <- copy 97/a screen:&:screen <- print screen:&:screen, a, 7/white ] # screen-should-contain shows everything screen-should-contain [ # 01234 .λa . . . . . ] # screen-should-contain-in-color filters out everything except the given # color, all you see is the 'a' in white. screen-should-contain-in-color 7/white, [ # 01234 . a . . . . . ] # ..and the λ in red. screen-should-contain-in-color 1/red, [ # 01234 .λ . . . . . ] ] # checks are inside scenario :(scenario screen_in_scenario_error) % Scenario_testing_scenario = true; % Hide_errors = true; scenario screen-in-scenario-error [ local-scope assume-screen 5/width, 3/height run [ a:char <- copy 97/a screen:&:screen <- print screen:&:screen, a ] screen-should-contain [ # 01234 .b . . . . . ] ] +error: F - screen-in-scenario-error: expected screen location (0, 0) to contain 98 ('b') instead of 97 ('a') :(scenario screen_in_scenario_color_error) % Scenario_testing_scenario = true; % Hide_errors = true; # screen-should-contain can check unicode characters in the fake screen scenario screen-in-scenario-color-error [ local-scope assume-screen 5/width, 3/height run [ a:char <- copy 97/a screen:&:screen <- print screen:&:screen, a, 1/red ] screen-should-contain-in-color 2/green, [ # 01234 .a . . . . . ] ] +error: F - screen-in-scenario-color-error: expected screen location (0, 0) to contain 'a' in color 2 instead of 1 :(scenarios run) :(scenario convert_names_does_not_fail_when_mixing_special_names_and_numeric_locations) % Scenario_testing_scenario = true; def main [ screen:num <- copy 1:num ] -error: mixing variable names and numeric addresses in main $error: 0 :(scenarios run_mu_scenario) //: It's easier to implement assume-screen and other similar scenario-only //: primitives if they always write to a fixed location. So we'll assign a //: single fixed location for the per-scenario screen, keyboard, file system, //: etc. Carve space for these fixed locations out of the reserved-for-test //: locations. :(before "End Globals") extern const int Max_variables_in_scenarios = Reserved_for_tests-100; int Next_predefined_global_for_scenarios = Max_variables_in_scenarios; :(before "End Reset") assert(Next_predefined_global_for_scenarios < Reserved_for_tests); :(before "End Globals") // Scenario Globals. extern const int SCREEN = next_predefined_global_for_scenarios(/*size_of(address:screen)*/2); // End Scenario Globals. :(code) int next_predefined_global_for_scenarios(int size) { int result = Next_predefined_global_for_scenarios; Next_predefined_global_for_scenarios += size; return result; } //: give 'screen' a fixed location in scenarios :(before "End Special Scenario Variable Names(r)") Name[r]["screen"] = SCREEN; //: make 'screen' always a raw location in scenarios :(before "End is_special_name Special-cases") if (s == "screen") return true; :(before "End Rewrite Instruc
/*
 * (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
 * See LICENSE file for license details.
 */

#define TAGS \
const char *tags[] = { "0", "1", "2", "3", "4", NULL };

#define DEFMODE			dotile /* dofloat */
#define DEFTAG			1 /* index */
#define FONT			"fixed"
#define BGCOLOR			"#666699"
#define FGCOLOR			"#eeeeee"
#define BORDERCOLOR		"#9999CC"
#define MODKEY			Mod1Mask
#define NUMLOCKMASK		Mod2Mask
#define MASTERW			60 /* percent */

#define KEYS \
static Key key[] = { \
	/* modifier			key		function	arguments */ \
	{ MODKEY,			XK_0,		view,		{ .i = 0 } }, \
	{ MODKEY,			XK_1,		view,		{ .i = 1 } }, \
	{ MODKEY,			XK_2,		view,		{ .i = 2 } }, \
	{ MODKEY,			XK_3,		view,		{ .i = 3 } }, \
	{ MODKEY,			XK_4,		view,		{ .i = 4 } }, \
	{ MODKEY,			XK_j,		focusnext,	{ 0 } }, \
	{ MODKEY,			XK_k,		focusprev,	{ 0 } }, \
	{ MODKEY,			XK_m,		togglemax,	{ 0 } }, \
	{ MODKEY,			XK_space,	togglemode,	{ 0 } }, \
	{ MODKEY,			XK_Return,	zoom,		{ 0 } }, \
	{ MODKEY|ControlMask,		XK_0,		toggleview,	{ .i = 0 } }, \
	{ MODKEY|ControlMask,		XK_1,		toggleview,	{ .i = 1 } }, \
	{ MODKEY|ControlMask,		XK_2,		toggleview,	{ .i = 2 } }, \
	{ MODKEY|ControlMask,		XK_3,		toggleview,	{ .i = 3 } }, \
	{ MODKEY|ControlMask,		XK_4,		toggleview,	{ .i = 4 } }, \
	{ MODKEY|ShiftMask,		XK_0,		tag,		{ .i = 0 } }, \
	{ MODKEY|ShiftMask,		XK_1,		tag,		{ .i = 1 } }, \
	{ MODKEY|ShiftMask,		XK_2,		tag,		{ .i = 2 } }, \
	{ MODKEY|ShiftMask,		XK_3,		tag,		{ .i = 3 } }, \
	{ MODKEY|ShiftMask,		XK_4,		tag,		{ .i = 4 } }, \
	{ MODKEY|ShiftMask,		XK_c,		killclient,	{ 0 } }, \
	{ MODKEY|ShiftMask,		XK_q,		quit,		{ 0 } }, \
	{ MODKEY|ShiftMask,		XK_Return,	spawn,		{ .cmd = "exec xterm" } }, \
	{ MODKEY|ControlMask|ShiftMask,	XK_0,		toggletag,	{ .i = 0 } }, \
	{ MODKEY|ControlMask|ShiftMask,	XK_1,		toggletag,	{ .i = 1 } }, \
	{ MODKEY|ControlMask|ShiftMask,	XK_2,		toggletag,	{ .i = 2 } }, \
	{ MODKEY|ControlMask|ShiftMask,	XK_3,		toggletag,	{ .i = 3 } }, \
	{ MODKEY|ControlMask|ShiftMask,	XK_4,		toggletag,	{ .i = 4 } }, \
};

#define RULES \
static Rule rule[] = { \
	/* class:instance regex		tags regex	isfloat */ \
	{ "Firefox.*",			"2",		False }, \
	{ "Gimp.*",			NULL,		True}, \
};
F); index += length; return result; } uint32_t raw_string_stream::peek() { assert(index < max); // caller must check bounds before calling 'get' uint32_t result = 0; int length = tb_utf8_char_to_unicode(&result, &buf[index]); assert(length != TB_EOF); return result; } void raw_string_stream::skip_whitespace_and_comments() { while (!at_end()) { if (isspace(peek())) get(); else if (peek() == '#') { // skip comment get(); while (peek() != '\n') get(); // implicitly also handles CRLF } else break; } } :(before "End Primitive Recipe Declarations") _DUMP_SCREEN, :(before "End Primitive Recipe Numbers") put(Recipe_ordinal, "$dump-screen", _DUMP_SCREEN); :(before "End Primitive Recipe Checks") case _DUMP_SCREEN: { break; } :(before "End Primitive Recipe Implementations") case _DUMP_SCREEN: { dump_screen(); break; } :(code) void dump_screen() { int screen_location = get_or_insert(Memory, SCREEN+/*skip address alloc id*/1) + /*skip payload alloc id*/1; reagent screen("x:screen"); // just to ensure screen.type is reclaimed int screen_data_location = find_element_location(screen_location, "data", screen.type, "check_screen"); // type: address:array:character assert(screen_data_location >= 0); //? cerr << "screen data is at location " << screen_data_location << '\n'; int screen_data_start = get_or_insert(Memory, screen_data_location+/*skip address alloc id*/1) + /*skip payload alloc id*/1; // type: array:character //? cerr << "screen data start is at " << screen_data_start << '\n'; int screen_width_location = find_element_location(screen_location, "num-columns", screen.type, "check_screen"); //? cerr << "screen width is at location " << screen_width_location << '\n'; int screen_width = get_or_insert(Memory, screen_width_location); //? cerr << "screen width: " << screen_width << '\n'; int screen_height_location = find_element_location(screen_location, "num-rows", screen.type, "check_screen"); //? cerr << "screen height is at location " << screen_height_location << '\n'; int screen_height = get_or_insert(Memory, screen_height_location); //? cerr << "screen height: " << screen_height << '\n'; int top_index_location= find_element_location(screen_location, "top-idx", screen.type, "check_screen"); //? cerr << "top of screen is at location " << top_index_location << '\n'; int top_index = get_or_insert(Memory, top_index_location); //? cerr << "top of screen is index " << top_index << '\n'; for (int i=0, row=top_index/screen_width; i < screen_height; ++i, row=(row+1)%screen_height) { cerr << '.'; int curr = screen_data_start+/*length*/1+row*screen_width* /*size of screen-cell*/2; for (int col = 0; col < screen_width; ++col) { if (get_or_insert(Memory, curr)) cerr << to_unicode(static_cast(get_or_insert(Memory, curr))); else cerr << ' '; curr += /*size of screen-cell*/2; } cerr << ".\n"; } }