% file: mmutil.sl v1.0 % Author: Marko Mahnič, % % Various utilities. This file is usually autoloaded. %!% \usage{Char get_char (String SomePrompt, String ValidChars)} %!% Displays SomePrompt and waits for user to type one of the ValidChars. %!% ValidChars are not case sensitive -- they are all converted to lower %!% case. Also Esc and ^G characters are appended to ValidChars to abort. %!% If \r is present in ValidChars, the default key is the leftmost %!% uppercase character. If there is no uppercase character, the %!% first character is the default. If we need get_char to return the \r %!% character, it must be the first character in ValidChars: %!% ValidChars: "abCdef" Return pressed ==> does not return %!% ValidChars: "abCdef\r" Return pressed ==> returns 'c' %!% ValidChars: "abcdef\r" Return pressed ==> returns 'a' %!% ValidChars: "\rabCdef" Return pressed ==> returns '\r' %!% It returns the key pressed (char typed in in lower case). define get_char (SomePrompt, ValidChars) { variable ch, default = '\r', pos; if (string_match (ValidChars, "\r", 1) > 1) { pos = string_match (ValidChars, "\\c[A-Z]", 1); if (pos == 0) pos = 1; default = tolower (int (substr (ValidChars, pos, 1))); } ValidChars = Sprintf ("%s\e", strlow (ValidChars), 1); %% Esc Ctrl-G flush (SomePrompt); while (input_pending (1) == 0); ch = tolower (getkey ()); while (is_substr (ValidChars, char (ch)) == 0) { beep (); while (input_pending (1) == 0); ch = tolower (getkey ()); } switch (ch) { case '\e': ch = ''; } %% Ctrl-G { case '\r': ch = default; } message (""); return ch; } %!% \usage{Void pause (String AMessage)} %!% Displays a message and waits for user to press Space, Return, Esc or ^G. define pause (AMessage) { get_char ("[Paused] " + AMessage, " \r"); pop (); } % \usage{Void menu_for_goto ()} define menu_for_goto () { variable ch; ch = get_char ("Goto Line/Routine/Bookmark/regeXp/grepFile/Wordcount", "lrbxfw"); switch (ch) {case 'l': goto_line_cmd (); } {case 'b': bkmrk_goto_mark (); } {case 'r': if (is_defined ("list_routines")) eval ("list_routines"); } {case 'x': if (is_defined ("occur")) eval ("occur"); } {case 'f': if (is_defined ("grep_text")) eval ("grep_text"); } {case 'w': if (is_defined ("grep_word_count")) eval ("grep_word_count"); } } % \usage{Void file_remove_tabs (Int tabsize)} define file_remove_tabs (tabsize) { variable i, spaces = Null_String; variable cur = 0, next = 0, prev = 0; if (tabsize < 1) return; push_spot (); bob (); while (fsearch ("\t")) { cur = what_column (); next = ((cur - 1) / tabsize + 1) * tabsize + 1; del (); cur = next - cur; !if (prev == cur) { spaces = " "; for (i = 1; i < cur; i++) spaces = spaces + " "; prev = cur; } insert (spaces); } pop_spot (); } % \usage{Void file_trim_eol ()} define file_trim_eol () { push_spot (); bob (); while (not (eobp ())) { eol (); trim (); go_down_1 (); } pop_spot (); } % \usage{Void c_file_indentify ()} define c_file_indentify () { bob (); while (eobp () == 0) { bol (); if (re_looking_at ("^[ \t]*$")) del_eol (); else indent_line (); go_down (1); } } % \usage{Void indent_region ()} define indent_region () { !if (markp()) return; check_region (1); variable endl = what_line(); exchange_point_and_mark(); variable line = what_line(); pop_mark(0); do { indent_line (); eol(); trim(); line++; } while (down(1) and line <= endl); pop_spot (); } % \usage{Void del_dup_lines ()} % removes consecutive duplicate lines in current buffer define del_dup_lines () { variable Line = Null_String; bob (); while (eobp () == 0) { mark_to_visible_eol (); Line = bufsubstr (); if (down (1) < 1) break; bol (); !if (Line == Null_String) { while (re_looking_at ("^" + Line + "$")) { del_through_eol (); bol (); } } } } % \usage{Void del_dup_lines_unsorted ()} % removes duplicate lines in current buffer define del_dup_lines_unsorted () { variable Line = Null_String; bob (); while (eobp () == 0) { mark_to_visible_eol (); Line = bufsubstr (); if (down (1) < 1) break; bol (); !if (Line == Null_String) { push_spot(); while (re_fsearch ("^" + Line + "$")) { del_through_eol (); bol (); } pop_spot(); } } } % \usage{Int re_replace (String RegExpFind, String Replacement)} %!% Replaces all occurences of strRegExpFind with strReplacement. %!% strReplacement can include substrings from strRegExpFind. %!% strRegExpFind is \0, first substring is \1, second is \2, etc. %!% Example: %!% input: ad e cf %!% re_replace ("\\([abc]\\)\\([def]\\)", "\\0:\\2\\1") %!% output: ad:da e cf:fc define re_replace (strRegExpFind, strReplacement) { push_spot (); while (re_fsearch (strRegExpFind) > 0) { !if (replace_match (strReplacement, 0)) return (0); } pop_spot (); return (1); } % \usage{Int stricmp (String a, String b)} define stricmp (a, b) { return strcmp (strup(a), strup(b)); } % \usage{Void two_windows (Int bottom_size)} %% Splits the screen into two windows with the bottom one having %% bottom_size lines. %% Bottom window becomes current. define two_windows (bottom_size) { if (bottom_size < 0) bottom_size = 0; if (bottom_size > SCREEN_HEIGHT) bottom_size = SCREEN_HEIGHT; onewindow(); splitwindow(); variable scrtop = window_info ('t'); if (scrtop < 3) otherwindow(); %% we are in the bottom window variable cursize = window_info ('r'); variable nenlarge = bottom_size - cursize; if (nenlarge >= 0) { loop (nenlarge) enlargewin(); } else { otherwindow(); loop (-nenlarge) enlargewin(); otherwindow(); } } % \usage{Void sum_region ()} define sum_region () { !if (markp()) return; %TODO: signal error check_region (1); variable c1, r1, c2, r2, tmp, l, c; c2 = what_column (); r2 = what_line(); exchange_point_and_mark(); c1 = what_column (); r1 = what_line(); if (c2 < c1) { tmp = c1; c1 = c2; c2 = tmp; } pop_mark (0); % 100 % 1.23 % -2 % -100.23 variable sum = 0; % TODO: Can I define a single pattern for integer and float? % variable number = "[+-]*[0-9]+\(.[0.9]*\)*"; % variable number = "[0-9]+\\(.[0-9]*\\)*"; variable number = "[+-]*[0-9]+"; tmp = re_fsearch (number); while (tmp) { c = what_column (); l = what_line (); if (l > r2) break; if (c >= c1 and c <= c2) { push_mark(); go_right (tmp - 1); sum = sum + integer (bufsubstr ()); } else go_right (tmp); tmp = re_fsearch (number); } vmessage ("Sum of numbers beginning inside marked rectangle is: %ld", sum); pop_spot(); } % \usage{Void make_lower ()} define make_lower () { if (not (markp())) { push_mark(); go_right (1); } xform_region ('d'); } % \usage{Void make_upper ()} define make_upper () { if (not (markp())) { push_mark(); go_right (1); } xform_region ('u'); } %% \usage{Void compare_lists (String buf1, String buf2, String buf_err)} %% Inserts into buf_err all the lines from buf1 that are not in buf2. define compare_lists (buf1, buf2, buf_err) { variable buf = whatbuf (); setbuf (buf1); eob (); variable lines = 1.0 * what_line (); variable cnt = 500; variable nDiff = 0; bob(); flush ("Working..."); variable s; while (not eobp()) { s = line_as_string(); setbuf (buf2); bob (); !if (re_fsearch("^" + s + "$")) { setbuf (buf_err); vinsert ("%s \n", s); nDiff ++; } setbuf (buf1); go_down(1); cnt--; if (cnt < 1) { cnt = 500; flush (sprintf ("Working... %.0f%% done. %d diffrences.", what_line() / lines * 100, nDiff)); } } setbuf (buf); flush ("100% done."); }