/* Welcome to the macro examples file! */

// The first function only serves as an introduction.
// It is bound to a keyboard shortcut, to make it easier,
// the rest of the macros can be invoked via Macro item in the menu.
macro "Start here" Ctrl+Alt+S {
	// Open this file
	EditFile("Macro", "Macro.usc");
	// Set cursor to the start
	SetCursor(0);
	// Now you can continue reading and exploring the rest of the examples...
}

// Macros can call functions defined via "fn" keyword anywhere (even other files, see Func.usc).
// This is usefull e.g. when you want to share some funcionality between several macros.
macro "Using functions" {
	// This function opens the example file, moves cursor at the end and appends some strings
	// generated by functions.
	EditFile("Macro","example.txt");
	MoveTextEnd();
	Insert("\n " + FuncA("C") + FuncB("D") + " \n");
}

fn FuncA(arg) {
	return FuncB(arg + "A");
}

/* Chapter 1: Methods controlling the editor */

macro "1 Editor":"1.1 File name" {
	ClearConsole();
	Echo("Currently edited file is '" + FileName() + "'");
}

macro "1 Editor":"1.2 Opening file" {
	// EditFile can be used with package and file names, as seen here, or it can ba called 
	// with single parameter containing full path to a file.
	EditFile("Macro","example.txt");
}

macro "1 Editor":"1.3 Closing file" {
	// Save the file first, to be sure
	SaveCurrentFile();
	// Now we can close it
	CloseFile();
}

/* Chapter 2: Methods for automatic text editing */

macro "2 Editing":"2.1 Select all" {
	// Again, make sure we use the testing file
	EditFile("Macro","example.txt");
	// This moves the cursor at the begining of file (the same can be achieved with SetCursor(0);)
	MoveTextBegin();
	// Now we move the cursor at the end of file. The parameter says that we want to select all
	// the text in between the previous and new position.
	MoveTextEnd(1);
}

macro "2 Editing":"2.2 Cursor position" {
	EditFile("Macro","example.txt");
	// We can get curent cursor position (in characters from start)...
	pos = GetCursor();
	// ... which can be used to calculate line number ...
	line = GetLine(pos);
	// ... and also position within the line
	col = GetColumn(pos);
	// Now we move at the end of file and insert a string summarizing what we found out
	MoveTextEnd();
	Insert("Line:"+to_string(line)+", Col:"+to_string(col)+", Pos"+to_string(pos)+"\n");
	// And finally, we put the cursor back where it originally was, just for users convenience
	SetCursor(pos);
}

macro "2 Editing":"2.3 File info" {
	EditFile("Macro","example.txt");
	pos = GetCursor();
	// Another set of informations we can get from the editor methods is how many text is there
	length = GetLength();
	// And also how many lines
	lines = GetLineCount();
	// Again, we append the info at the end and return to original position
	MoveTextEnd();
	Insert("Length:"+to_string(length)+", Lines:"+to_string(lines)+"\n");
	SetCursor(pos);
}

macro "2 Editing":"2.4 Complex example" {
	/* This function analyzes a document (example.txt) and prints a histogram of character 
	 * usage at the bottom. It could probably be implemented better, faster or both,
	 * but it is intentionaly left as is, to demonstrate that even simple macro language 
	 * can be used to achieve quite complex tasks.
	 */
	// how many lines should we use to print the histogram
	height = 20;
	// set active file to the example text
	EditFile("Macro", "example.txt");
	// remember cursor position, so we can return it at the end
	pos = GetCursor();
	// this is a little trick to make sure Esc knows that hist is a map, not an array
	hist[""] = 0;
	// iterate over entire document and count letters
	length = GetLength();
	for(i=0; i<length; i++){
		x = ToLower(Get(i));
		// change the key for non-printable
		if(x[0]<=32)
			x="";
		// initialize if it is first encounter, otherwise just increse value
		if(is_void(hist[x]))
			hist[x] = 1;
		else
			hist[x]++;
	}
	// delete non-printable
	hist[""] = void;
	// make a line of '=' with same length as we have columns
	sep = "+" + len(hist) * "-" + "+";
	// insert top line
	MoveTextEnd();
	Insert("\n"+sep+"\n");
	MoveTextEnd();
	// compute maximum for scaling
	max = height;
	for(i in hist)
		if(hist[i]>max) 
			max = hist[i];
	// get sort order
	k = sort(keys(hist));
	// plot the histogram, left to right, top to bottom
	for(i=height; i>0; --i){
		Insert("|");
		MoveRight();
		for(j in k){
			if(hist[k[j]]/max*height >= i)
				Insert("#");
			else
				Insert(" ");
			MoveRight();
		}
		// print y-axis legend
		Insert("|"+to_string(int(i*max/height))+"\n");
		MoveTextEnd();
	}
	//insert bottom line
	Insert(sep+"\n");
	MoveTextEnd();
	// print x-axis legend
	Insert(" ");
	MoveRight();
	for(j in k) {
		Insert(k[j]);
		MoveRight();
	}
	Insert("\n");
	// return cursor to original position
	SetCursor(pos);
}

macro "3 User interaction":"3.1 Using console" {
	// It is a good idea to clean the console before printing something in it, because text
	// left from previous actions might confuse the user
	ClearConsole();
	// You already seen Echo being used to inform user in some of the examples above...
	// Important point is, that the console will be shown if it is hidden as soon
	// as you Echo() something.
	Echo("Hello wolrd!", "This is just a test...");
}

macro "3 User interaction":"3.2 Input" {
	ClearConsole();
	// The Input() function can be called to get some values from user. It returns array 
	// of strings containing the values entered into the dialog.
	a = Input("Some number","Some string");
	// If you want to use it to get some number, you need to convert it from string and check
	// that it was really a number
	n = to_number(a[0]);
	if (is_void(n)){
		Echo("ERROR: '" + a[0] + "' is not a number.");
		return;
	}
	// Now you can safely use the obtained data
	Echo("The entered number was "+to_string(n),
	     "The string was '" + a[1] + "'");
}

/* Chapter 4: Methods that give you informations about the development environment */

macro "4 Informative":"4.1 Package info" {
	ClearConsole();
	// There are 4 functions that can be used to find out what packages and files current 
	// project consists of. 
	Echo("ActivePackage()=\"" + ActivePackage() + "\"",
	     "MainPackage()=\"" + MainPackage() + "\"",
	     "PackageDir()=\"" + PackageDir() + "\"",
	     "PackageDir(\"plugin/z\")=\"" + PackageDir("plugin/z") + "\"",
	     "PackageFiles()=" + to_string(PackageFiles()),
	     "PackageFiles(\"plugin/z\")=" + to_string(PackageFiles("plugin/z")));
	// Additionaly, the two of them which accept package name as a parameter can be also used
	// to query packages not used in current project
	Echo("PackageDir(\"plugin/gif\")=\"" + PackageDir("plugin/gif") + "\"",
	     "PackageFiles(\"plugin/gif\")=" + to_string(PackageFiles("plugin/gif")));
}

macro "4 Informative":"4.2 Build config info" {
	ClearConsole();
	// Another four methods inform about the build environment settings
	Echo("Assembly()=\"" + Assembly() + "\"",
	     "Flags()=" + to_string(Flags()),
	     "BuildMethod()=\"" + BuildMethod() + "\"",
	     "BuildMode()=\"" + to_string(BuildMode()) + "\"");
	// You might have noticed that BuildMode() returns number, but it can be easily converted:
	modes = [ "Debug", "Optional", "Speed", "Size" ];
	Echo("Build mode is set to '" + modes[BuildMode()] + "'.");
}

macro "5 Executing/Building":"5.1 Execute" {
	ClearConsole();
	// An external command can be executed with Execute, the output will be printed in console
	Execute("echo Hello world");
}

macro "5 Executing/Building":"5.2 Launch" {
	// this should work on Win and do nothing on Linux
	Launch("cmd.exe");
	// this should do nothing on Win and work on Linux
	Launch("/usr/bin/xterm");
}

macro "5 Executing/Building":"5.3 Build" {
	ClearConsole();
	// Build can be used to automatically build current project.
	Build();
}

macro "5 Executing/Building":"5.4 BuildProject" {
	ClearConsole();
	// Get .upp file location for another package
	upp = PackageDir("umk") + "/umk.upp";
	// Build that package with SSE2 build flag
	BuildProject(upp, "SSE2");
}

