⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 inputline.cc

📁 Unix下的MUD客户端程序
💻 CC
字号:
// The input line#include "mcl.h"#include "cui.h"#include "Interpreter.h"#include <sys/stat.h>// A history for one input line// This class is used internally by InputLineclass History {public:    History(int _id);    ~History();        void add (const char *s,time_t);			// Add this string    const char * get (int no, time_t *timestamp);			// Get this string.    int id;								// Id number    private:        char **strings;						// Array of strings    time_t *timestamps;    int max_history;					// Max number of strings    int current;						// Current place we will insert a new};History::History(int _id) : id (_id), current(0) {	max_history = config->getOption(opt_histsize);    strings = new (char*)[max_history];    timestamps = new time_t[max_history];		// Hmm, not sure about this	memset(strings,0, max_history * sizeof(char*));}History::~History() {    delete[] strings;    delete[] timestamps;}void History::add(const char *s,time_t t) {	// Don't store multiple strings that are exactly the same	if (current > 0 && !strcmp(s,strings[(current-1) % max_history]))		return;		if (strings[current % max_history])		free(strings[current % max_history]);	    strings[current % max_history] = strdup(s);    timestamps[current % max_history] = t;	current++;}// getting number 1 gets you the LAST lineconst char * History::get(int count, time_t* timestamp) {    if (count > min(current, max_history))        return NULL;        if (timestamp)        *timestamp = timestamps[(current - count) % max_history];    return strings[(current - count) % max_history];}// This class has a set of history arrays// This is so they can save between invokactions of the input line in// question without requiring globalsclass HistorySet {public:    ~HistorySet()  {        if (config->getOption(opt_save_history)) {            FILE *fp = fopen(Sprintf("%s/.mcl/history", getenv("HOME")), "w");            if (fp) {                const char *s;                time_t t;                fchmod(fileno(fp), 0600);                FOREACH(History *,h,hist_list)                    for (int i = config->getOption(opt_histsize) ; i > 0; i--)                        if ((s = get((history_id)h->id,i, &t)))                            fprintf(fp, "%d %ld %s\n", h->id, t, s);                fclose(fp);            }        }                for (History *h = hist_list.rewind(); h; h = hist_list.next()) {            delete h;            hist_list.remove(h);        }    }        void loadHistory() {        if (config->getOption(opt_save_history)) {            FILE *fp = fopen(Sprintf("%s/.mcl/history", getenv("HOME")), "r");            if (fp) {                int id;                time_t t;                char buf[1024];                                while (3 == fscanf(fp, "%d %ld %1024[^\n]", &id, &t, buf))                    add((history_id)id,buf,t);                fclose(fp);            }        }    }        const char *get (history_id id, int count, time_t* timestamp) {        return find(id)->get(count, timestamp);            }        void add (history_id id, const char *s, time_t t = 0) {        find(id)->add(s,t ? t : current_time);    }    private:    List<History*> hist_list;        History * find(int id) {        for (History *h = hist_list.rewind(); h; h = hist_list.next())            if (h->id == id)                return h;                History *new_hist = new History(id);        hist_list.insert(new_hist);        return new_hist;    }};static HistorySet history;void load_history() {    history.loadHistory();}class InputHistorySelection : public Selection{public:    InputHistorySelection(Window *parent, int w, int h, int x, int y, InputLine& _input, bool _enterExecutes, history_id _historyId) : Selection(parent,w,h,x,y),        inputLine(_input), enterExecutes(_enterExecutes), historyId(_historyId) {            const char *s;            for (int i = 1; (s = history.get(historyId,i, NULL)); i++)                prepend_string(s);        }        virtual void idle() {        doSelect(getSelection());        force_update();    }        virtual void doSelect(int no) {        time_t t;        char buf[64];        assert(history.get(historyId, getCount() - no, &t));        strftime(buf, sizeof(buf), "%H:%M:%S", localtime(&t));        const char *unit = "second";        int n = current_time - t;        if (n > 120) {            n /= 60;            unit = "minute";            if (n > 120) {                n /= 60;                unit = "hour";                if (n > 48) {                    n /= 24;                    unit = "day";                }            }        }                set_bottom_message(Sprintf("Executed on: %s (%d %s%s ago)", buf, n, unit, n == 1 ? "" : "s"));    }        virtual void doChoose(int no, int key) {        const char *s = history.get(historyId, getCount() - no,NULL);        assert(s != NULL);        inputLine.set(s);        if (enterExecutes && key == keyEnter)            inputLine.keypress(keyEnter);        die();    }    private:    InputLine& inputLine; // Input line to do the changes on    bool enterExecutes;   // Enter sends \r to the input line too    history_id historyId;     // History to get the data from};const char *szDefaultPrompt = "mcl>";InputLine::InputLine(Window *_parent, int _w, int _h, Style _style, int _x, int _y, history_id _id): Window(_parent, _w, _h, _style, _x, _y),cursor_pos(0), max_pos(0), left_pos(0), ready(false), id(_id), history_pos(0){	set_default_prompt();}void InputLine::set_default_prompt() {	strcpy(prompt_buf, szDefaultPrompt);	adjust();	dirty = true;}void InputLine::set(const char *s) {	strcpy (input_buf, s);	max_pos = strlen(input_buf);	cursor_pos = max_pos;    left_pos = 0;	adjust();	dirty = true;}void MainInputLine::set (const char *s) {    InputLine::set(s);    if (*s == NUL) { // clear, go back to standard size        move(0, parent->height-1);        resize(width, 1);        output->move(0,0);    }}// Handle a keypressbool InputLine::keypress(int key) {    if (ready)        return true;        embed_interp->set("Key", key);    dirty = true; // let's just assume this to make things easier        int prev_len = max_pos;        if (embed_interp->run_quietly("keypress", input_buf, input_buf)) {        // This is tough - what do we adjust here        int new_len = strlen(input_buf);        max_pos += (new_len - prev_len);        cursor_pos += (new_len - prev_len);        cursor_pos = max(cursor_pos, 0);                // set Key to 0 if keypress handled. Ugh        if ((key = embed_interp->get_int("Key")) == 0)            return true;    }        if (key == key_ctrl_h || key == key_backspace) {        if (max_pos == 0 || cursor_pos == 0)            ; //status->setf ("Nothing to delete");        else if (cursor_pos == max_pos) {            max_pos--;            cursor_pos--;        }        else { // we are in the middle of the input line            memmove(input_buf + cursor_pos - 1, input_buf + cursor_pos, max_pos - cursor_pos);            cursor_pos--;            max_pos--;        }                left_pos = max(0,left_pos-1);            }    else if (key == key_ctrl_a) {        cursor_pos = left_pos = 0;    }    else if (key == key_ctrl_c) { // save line to history but don't execute        if (strlen(input_buf) > 0) {            history.add (id, input_buf);            set("");            status->setf("Line added to history but not sent");        }    }    else if (key == key_ctrl_j || key == key_ctrl_k) { // delete until EOL        max_pos = cursor_pos;    }    else if (key == key_escape) {        set("");    }    else if (key == key_ctrl_e) { // go to eol        cursor_pos = max_pos;        adjust();    }    else if (key == key_ctrl_u) {        memmove(input_buf, input_buf+cursor_pos, max_pos - cursor_pos);        max_pos -= cursor_pos;        cursor_pos = 0;        adjust();    }    else if (key == key_ctrl_w) { // Delete word        // How long is the word?        int bow = cursor_pos - 1;                while (bow > 0 && isspace(input_buf[bow]))            bow--;        while (bow > 0 && !isspace(input_buf[bow]))            bow--;        if (bow > 0)            bow++; // Don't eat the space        if (bow >= 0 ) {            memmove(input_buf+bow, input_buf+cursor_pos, max_pos - cursor_pos);            max_pos -= cursor_pos - bow;            cursor_pos = bow;            adjust();        }    }    else if (key == key_delete) { // delete to the right        if (cursor_pos == max_pos)            status->setf ("Nothing to the right of here");        else  {            memmove(input_buf+cursor_pos, input_buf + cursor_pos + 1, max_pos - cursor_pos);            max_pos--;        }    }    else if (key == keyEnter) { // return. finish this line        ready = true;        input_buf[max_pos] = NUL;                if ((int)strlen(input_buf) >= config->getOption(opt_histwordsize))            history.add (id, input_buf);                history_pos = 0; // Reset history cycling        cursor_pos = 0;                max_pos = left_pos = 0;        ready = false;                move(0, parent->height-1);        output->move(0,0);        resize(width, 1);                execute();    }        else if (key >= ' ' && key < 256) { // Normal key. Just insert        if (max_pos < MAX_INPUT_BUF-1) {            if (cursor_pos == max_pos) { // We are already at EOL                input_buf[max_pos++] = key;                cursor_pos++;            } else { // We are inserting somewhere in the middle                memmove(input_buf + cursor_pos +1, input_buf + cursor_pos, max_pos - cursor_pos);                max_pos++;                input_buf[cursor_pos++] = key;            }            adjust();                    }        else            status->setf ("The input buffer is full");    }    else if (key == key_arrow_left) {        if (cursor_pos == 0)            status->setf ("Already at the far left of the input line.");        else        {            cursor_pos--;            left_pos = max(0,left_pos-1);        }    }    else if (key == key_arrow_right) {        if (cursor_pos == max_pos)            status->setf ("Already at the end of the input line.");        else        {            cursor_pos++;            if (cursor_pos > 7*width/8) // scroll only when we are approaching right margin                adjust();        }    }    else if (key == key_arrow_up) { // recall        int lines;                if (id == hi_none)            status->setf ("No history available");        else if (id != hi_generic && (lines = config->getOption(opt_historywindow)))        {            lines = min (parent->height-4, lines);                        if (!history.get(id,1, NULL))                status->setf ("There are no previous commands");            else            {                if (lines > 3)                    (void)new InputHistorySelection(parent, width, lines, 0, -(lines+2), *this, true, id);                // Window is to small; we need to cycle history in the input box                else  {                    (void)new MessageBox(screen, "Sorry, no history available", 0);                }            }        }        else {            const char *s;            if (!(s = history.get(id, history_pos+1, NULL)))                status->setf ("No previous history");            else  {                set(s);                history_pos++;            }        }    }    else if (key == key_arrow_down) {        const char *s;        if (id == hi_none)            status->setf("No history available");        else if (history_pos == 1 || !(s = history.get(id,history_pos-1, NULL)))        {            status->setf ("No next history");            history_pos = 0;        }        else        {            set(s);            history_pos--;        }    }        else        return false;        input_buf[max_pos] = NUL;        return true;}void InputLine::redraw() {    int prompt_len = strlen(prompt_buf);        gotoxy(0,0);    set_color(config->getOption(opt_inputcolor));    input_buf[max_pos] = NUL;    if (config->getOption(opt_multiinput) && isExpandable()) {        printf("%s%s%*s", prompt_buf, input_buf, (height*width)-prompt_len-max_pos, "");        if (is_focused())            set_cursor((cursor_pos+prompt_len)%width, (cursor_pos+prompt_len)/width);    } else {        printf("%s%s%-*.*s", prompt_buf, left_pos ? "<" : "",               width-1-prompt_len + (left_pos ? 0 : 1),                width-1-prompt_len + (left_pos ? 0 : 1),                input_buf+left_pos);                if (is_focused())            set_cursor(cursor_pos+prompt_len-left_pos + (left_pos ? 1 : 0) ,0);    }            dirty = false;}// If an input line is ready, move it over to bufbool InputLine::getline(char *buf, bool fForce){	if (!ready && !fForce)		return false;	else	{		ready = false;		if (fForce)			input_buf[max_pos]  = NUL;					strcpy (buf, input_buf);		max_pos = left_pos = 0;		return true;	}}void InputLine::adjust() {    if (config->getOption(opt_multiinput) && isExpandable()) {        while ( ((int)strlen(prompt_buf) + max_pos)/width >= height) {            move(parent_x, parent_y - 1);            resize(width, height+1);            output->move(0, 1-height);        }    }    else        while (1 + (int) strlen (prompt_buf) + cursor_pos - left_pos >= width)            left_pos++;}void  InputLine::set_prompt (const char *s) {    const char *in;    char   *out;        for (in = s, out = prompt_buf; *in && out-prompt_buf < MAX_PROMPT_BUF-1; in++)        if (*in == (signed char) SET_COLOR)            in++;        else if (*in == '\n' || *in == '\r')            *out++ = ' ';        else            *out++ = *in;        *out++ = NUL;            dirty = true;}MainInputLine::MainInputLine():InputLine(screen, wh_full, 1, None, 0, -1, hi_main_input) {    parent->focus(this);}void MainInputLine::execute() {    embed_interp->run_quietly("sys/userinput", input_buf, input_buf);    if (config->getOption(opt_expand_semicolon))        interpreter.add(input_buf, EXPAND_INPUT|EXPAND_SEMICOLON);    else        interpreter.add(input_buf, EXPAND_INPUT);        if (config->getOption (opt_echoinput))		// echo input if wanted        output->printf ("%c>> %s\n", SOFT_CR, input_buf);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -