Command history separated from Console.

develop
Petr Mrázek 2011-08-13 14:42:09 +02:00
parent 1cbcb99dd5
commit 81e6bce92c
10 changed files with 178 additions and 116 deletions

@ -140,6 +140,23 @@ namespace DFHack
{ {
//sync(); //sync();
} }
private:
bool read_char(unsigned char & out)
{
while(1)
{
if (select(FD_SETSIZE, &descriptor_set, NULL, NULL, NULL) < 0)
return false;
if (FD_ISSET(STDIN_FILENO, &descriptor_set))
{
// read byte from stdin
read(STDIN_FILENO, &out, 1);
return true;
}
if (FD_ISSET(exit_pipe[0], &descriptor_set))
return false;
}
}
protected: protected:
int sync() int sync()
{ {
@ -267,7 +284,7 @@ namespace DFHack
/// beep. maybe? /// beep. maybe?
//void beep (void); //void beep (void);
/// A simple line edit (raw mode) /// A simple line edit (raw mode)
int lineedit(const std::string& prompt, std::string& output, mutex * lock) int lineedit(const std::string& prompt, std::string& output, mutex * lock, CommandHistory & ch)
{ {
output.clear(); output.clear();
this->prompt = prompt; this->prompt = prompt;
@ -288,7 +305,7 @@ namespace DFHack
if(state == con_lineedit) if(state == con_lineedit)
return -1; return -1;
state = con_lineedit; state = con_lineedit;
count = prompt_loop(lock); count = prompt_loop(lock,ch);
state = con_unclaimed; state = con_unclaimed;
disable_raw(); disable_raw();
print("\n"); print("\n");
@ -299,19 +316,6 @@ namespace DFHack
return count; return count;
} }
} }
/// add a command to the history
void history_add(const std::string& command)
{
// if current command = last in history -> do not add. Always add if history is empty.
if(!history.empty() && history.front() == command)
return;
history.push_front(command);
if(history.size() > 100)
history.pop_back();
}
/// clear the command history
void history_clear();
int enable_raw() int enable_raw()
{ {
struct termios raw; struct termios raw;
@ -381,7 +385,7 @@ namespace DFHack
if (::write(STDIN_FILENO,seq,strlen(seq)) == -1) return; if (::write(STDIN_FILENO,seq,strlen(seq)) == -1) return;
} }
int prompt_loop(mutex * lock) int prompt_loop(mutex * lock, CommandHistory & history)
{ {
int fd = STDIN_FILENO; int fd = STDIN_FILENO;
size_t plen = prompt.size(); size_t plen = prompt.size();
@ -391,18 +395,20 @@ namespace DFHack
/* The latest history entry is always our current buffer, that /* The latest history entry is always our current buffer, that
* initially is just an empty string. */ * initially is just an empty string. */
const std::string empty; const std::string empty;
history_add(empty); history.add(empty);
if (::write(fd,prompt.c_str(),prompt.size()) == -1) return -1; if (::write(fd,prompt.c_str(),prompt.size()) == -1) return -1;
while(1) while(1)
{ {
char c; unsigned char c;
int nread; int isok;
char seq[2], seq2; unsigned char seq[2], seq2;
lock->unlock(); lock->unlock();
nread = ::read(fd,&c,1); if(!read_char(c))
{
lock->lock();
return -2;
}
lock->lock(); lock->lock();
if (nread <= 0) return raw_buffer.size();
/* Only autocomplete when the callback is set. It returns < 0 when /* Only autocomplete when the callback is set. It returns < 0 when
* there was an error reading from fd. Otherwise it will return the * there was an error reading from fd. Otherwise it will return the
* character that should be handled next. */ * character that should be handled next. */
@ -429,7 +435,7 @@ namespace DFHack
switch(c) switch(c)
{ {
case 13: // enter case 13: // enter
history.pop_front(); history.remove();
return raw_buffer.size(); return raw_buffer.size();
case 3: // ctrl-c case 3: // ctrl-c
errno = EAGAIN; errno = EAGAIN;
@ -445,10 +451,10 @@ namespace DFHack
break; break;
case 27: // escape sequence case 27: // escape sequence
lock->unlock(); lock->unlock();
if (::read(fd,seq,2) == -1) if(!read_char(seq[0]) || !read_char(seq[1]))
{ {
lock->lock(); lock->lock();
break; return -2;
} }
lock->lock(); lock->lock();
if(seq[0] == '[') if(seq[0] == '[')
@ -513,10 +519,10 @@ namespace DFHack
{ {
// extended escape // extended escape
lock->unlock(); lock->unlock();
if (::read(fd,&seq2,1) == -1) if(!read_char(seq2))
{ {
lock->lock(); lock->lock();
return -1; return -2;
} }
lock->lock(); lock->lock();
if (seq[1] == '3' && seq2 == '~' ) if (seq[1] == '3' && seq2 == '~' )
@ -579,7 +585,6 @@ namespace DFHack
return raw_buffer.size(); return raw_buffer.size();
} }
FILE * dfout_C; FILE * dfout_C;
std::deque <std::string> history;
bool supported_terminal; bool supported_terminal;
// state variables // state variables
bool rawmode; // is raw mode active? bool rawmode; // is raw mode active?
@ -593,6 +598,9 @@ namespace DFHack
std::string prompt; // current prompt string std::string prompt; // current prompt string
std::string raw_buffer; // current raw mode buffer std::string raw_buffer; // current raw mode buffer
int raw_cursor; // cursor position in the buffer int raw_cursor; // cursor position in the buffer
// thread exit mechanism
int exit_pipe[2];
fd_set descriptor_set;
}; };
} }
@ -629,6 +637,11 @@ bool Console::init(bool sharing)
std::cin.tie(this); std::cin.tie(this);
clear(); clear();
d->supported_terminal = !isUnsupportedTerm() && isatty(STDIN_FILENO); d->supported_terminal = !isUnsupportedTerm() && isatty(STDIN_FILENO);
// init the exit mechanism
pipe(d->exit_pipe);
FD_ZERO(&d->descriptor_set);
FD_SET(STDIN_FILENO, &d->descriptor_set);
FD_SET(d->exit_pipe[0], &d->descriptor_set);
inited = true; inited = true;
} }
@ -641,6 +654,8 @@ bool Console::shutdown(void)
d->disable_raw(); d->disable_raw();
d->print("\n"); d->print("\n");
inited = false; inited = false;
// kill the thing
close(d->exit_pipe[1]);
return true; return true;
} }
@ -727,20 +742,12 @@ void Console::cursor(bool enable)
d->cursor(enable); d->cursor(enable);
} }
// push to front, remove from back if we are above maximum. ignore immediate duplicates int Console::lineedit(const std::string & prompt, std::string & output, CommandHistory & ch)
void Console::history_add(const std::string & command)
{
lock_guard <mutex> g(*wlock);
if(inited)
d->history_add(command);
}
int Console::lineedit(const std::string & prompt, std::string & output)
{ {
lock_guard <mutex> g(*wlock); lock_guard <mutex> g(*wlock);
int ret = -2; int ret = -2;
if(inited) if(inited)
ret = d->lineedit(prompt,output,wlock); ret = d->lineedit(prompt,output,wlock,ch);
return ret; return ret;
} }

@ -250,7 +250,7 @@ namespace DFHack
SetConsoleCursorPosition(console_out, inf.dwCursorPosition); SetConsoleCursorPosition(console_out, inf.dwCursorPosition);
} }
int prompt_loop(mutex * lock) int prompt_loop(mutex * lock, CommandHistory & history)
{ {
raw_buffer.clear(); // make sure the buffer is empty! raw_buffer.clear(); // make sure the buffer is empty!
size_t plen = prompt.size(); size_t plen = prompt.size();
@ -259,7 +259,7 @@ namespace DFHack
// The latest history entry is always our current buffer, that // The latest history entry is always our current buffer, that
// initially is just an empty string. // initially is just an empty string.
const std::string empty; const std::string empty;
history_add(empty); history.add(empty);
CONSOLE_SCREEN_BUFFER_INFO inf = { 0 }; CONSOLE_SCREEN_BUFFER_INFO inf = { 0 };
GetConsoleScreenBufferInfo(console_out, &inf); GetConsoleScreenBufferInfo(console_out, &inf);
@ -280,7 +280,7 @@ namespace DFHack
switch (rec.Event.KeyEvent.wVirtualKeyCode) switch (rec.Event.KeyEvent.wVirtualKeyCode)
{ {
case VK_RETURN: // enter case VK_RETURN: // enter
history.pop_front(); history.remove();
return raw_buffer.size(); return raw_buffer.size();
case VK_BACK: // backspace case VK_BACK: // backspace
if (raw_cursor > 0 && raw_buffer.size() > 0) if (raw_cursor > 0 && raw_buffer.size() > 0)
@ -359,13 +359,13 @@ namespace DFHack
} }
} }
} }
int lineedit(const std::string & prompt, std::string & output, mutex * lock) int lineedit(const std::string & prompt, std::string & output, mutex * lock, CommandHistory & ch)
{ {
output.clear(); output.clear();
int count; int count;
state = con_lineedit; state = con_lineedit;
this->prompt = prompt; this->prompt = prompt;
count = prompt_loop(lock); count = prompt_loop(lock, ch);
if(count != -1) if(count != -1)
output = raw_buffer; output = raw_buffer;
state = con_unclaimed; state = con_unclaimed;
@ -373,21 +373,8 @@ namespace DFHack
return count; return count;
} }
// push to front, remove from back if we are above maximum. ignore immediate duplicates
void history_add(const std::string & command)
{
// if current command = last in history -> do not add. Always add if history is empty.
if(!history.empty() && history.front() == command)
return;
history.push_front(command);
if(history.size() > 100)
history.pop_back();
}
FILE * dfout_C; FILE * dfout_C;
int rawmode; int rawmode;
std::deque <std::string> history;
HANDLE console_in; HANDLE console_in;
HANDLE console_out; HANDLE console_out;
HWND ConsoleWindow; HWND ConsoleWindow;
@ -556,20 +543,12 @@ void Console::cursor(bool enable)
d->cursor(enable); d->cursor(enable);
} }
// push to front, remove from back if we are above maximum. ignore immediate duplicates int Console::lineedit(const std::string & prompt, std::string & output, CommandHistory & ch)
void Console::history_add(const std::string & command)
{
lock_guard <mutex> g(*wlock);
if(inited)
d->history_add(command);
}
int Console::lineedit(const std::string & prompt, std::string & output)
{ {
wlock->lock(); wlock->lock();
int ret = -2; int ret = -2;
if(inited) if(inited)
ret = d->lineedit(prompt,output,wlock); ret = d->lineedit(prompt,output,wlock,ch);
wlock->unlock(); wlock->unlock();
return ret; return ret;
} }

@ -133,6 +133,8 @@ void fIOthread(void * iodata)
IODATA * iod = ((IODATA*) iodata); IODATA * iod = ((IODATA*) iodata);
Core * core = iod->core; Core * core = iod->core;
PluginManager * plug_mgr = ((IODATA*) iodata)->plug_mgr; PluginManager * plug_mgr = ((IODATA*) iodata)->plug_mgr;
CommandHistory main_history;
main_history.load("dfhack.history");
Console & con = core->con; Console & con = core->con;
if(plug_mgr == 0 || core == 0) if(plug_mgr == 0 || core == 0)
{ {
@ -145,7 +147,7 @@ void fIOthread(void * iodata)
while (true) while (true)
{ {
string command = ""; string command = "";
int ret = con.lineedit("[DFHack]# ",command); int ret = con.lineedit("[DFHack]# ",command, main_history);
if(ret == -2) if(ret == -2)
{ {
cerr << "Console is shutting down properly." << endl; cerr << "Console is shutting down properly." << endl;
@ -159,7 +161,8 @@ void fIOthread(void * iodata)
else if(ret) else if(ret)
{ {
// a proper, non-empty command was entered // a proper, non-empty command was entered
con.history_add(command); main_history.add(command);
main_history.save("dfhack.history");
} }
// cut the input into parts // cut the input into parts
vector <string> parts; vector <string> parts;
@ -387,7 +390,7 @@ Core::Core()
hotkey_set = false; hotkey_set = false;
HotkeyMutex = 0; HotkeyMutex = 0;
HotkeyCond = 0; HotkeyCond = 0;
misc_data_mutex=0; misc_data_mutex=0;
}; };
bool Core::Init() bool Core::Init()

@ -25,7 +25,12 @@ distribution.
#pragma once #pragma once
#include "dfhack/Pragma.h" #include "dfhack/Pragma.h"
#include "dfhack/Export.h" #include "dfhack/Export.h"
#include <ostream> #include <deque>
#include <fstream>
#include <llimits.h>
#include <assert.h>
#include <iostream>
#include <string>
namespace tthread namespace tthread
{ {
class mutex; class mutex;
@ -34,6 +39,74 @@ namespace tthread
} }
namespace DFHack namespace DFHack
{ {
class CommandHistory
{
public:
CommandHistory(std::size_t capacity = 100)
{
this->capacity = capacity;
}
bool load (const char * filename)
{
std::string reader;
std::ifstream infile(filename);
if(infile.bad())
return false;
std::string s;
while(std::getline(infile, s))
{
if(s.empty())
continue;
history.push_back(s);
}
return true;
}
bool save (const char * filename)
{
std::ofstream outfile (filename);
if(outfile.bad())
return false;
for(auto iter = history.begin();iter < history.end(); iter++)
{
outfile << *iter << std::endl;
}
outfile.close();
return true;
}
/// add a command to the history
void add(const std::string& command)
{
// if current command = last in history -> do not add. Always add if history is empty.
if(!history.empty() && history.front() == command)
return;
history.push_front(command);
if(history.size() > capacity)
history.pop_back();
}
/// clear the command history
void clear()
{
history.clear();
}
/// get current history size
std::size_t size()
{
return history.size();
}
/// get pointer to a particular history item
std::string & operator[](std::size_t index)
{
assert(index < history.size());
return history[index];
}
void remove( void )
{
history.pop_front();
}
private:
std::size_t capacity;
std::deque <std::string> history;
};
class Private; class Private;
class DFHACK_EXPORT Console : public std::ostream class DFHACK_EXPORT Console : public std::ostream
{ {
@ -91,11 +164,7 @@ namespace DFHack
/// beep. maybe? /// beep. maybe?
//void beep (void); //void beep (void);
/// A simple line edit (raw mode) /// A simple line edit (raw mode)
int lineedit(const std::string& prompt, std::string& output); int lineedit(const std::string& prompt, std::string& output, CommandHistory & history );
/// add a command to the history
void history_add(const std::string& command);
/// clear the command history
void history_clear();
private: private:
Private * d; Private * d;
tthread::mutex * wlock; tthread::mutex * wlock;

@ -89,13 +89,14 @@ DFhackCExport command_result plugin_onupdate ( Core * c )
void InterpreterLoop(Core* c) void InterpreterLoop(Core* c)
{ {
Console &con=c->con; Console &con=c->con;
DFHack::CommandHistory hist;
lua::state s=lua::glua::Get(); lua::state s=lua::glua::Get();
string curline; string curline;
con.print("Type quit to exit interactive mode\n"); con.print("Type quit to exit interactive mode\n");
con.lineedit(">>",curline); con.lineedit(">>",curline,hist);
while (curline!="quit") { while (curline!="quit") {
con.history_add(curline); hist.add(curline);
try try
{ {
s.loadstring(curline); s.loadstring(curline);
@ -104,10 +105,10 @@ void InterpreterLoop(Core* c)
catch(lua::exception &e) catch(lua::exception &e)
{ {
con.printerr("Error:%s\n",e.what()); con.printerr("Error:%s\n",e.what());
c->con.printerr("%s",lua::DebugDump(lua::glua::Get()).c_str()); c->con.printerr("%s",lua::DebugDump(lua::glua::Get()).c_str());
s.settop(0); s.settop(0);
} }
con.lineedit(">>",curline); con.lineedit(">>",curline,hist);
} }
s.settop(0); s.settop(0);
} }
@ -125,7 +126,7 @@ DFhackCExport command_result lua_run (Core * c, vector <string> & parameters)
catch(lua::exception &e) catch(lua::exception &e)
{ {
con.printerr("Error:%s\n",e.what()); con.printerr("Error:%s\n",e.what());
c->con.printerr("%s",lua::DebugDump(lua::glua::Get()).c_str()); c->con.printerr("%s",lua::DebugDump(lua::glua::Get()).c_str());
} }
} }
else else
@ -150,7 +151,7 @@ DFhackCExport command_result dfusion (Core * c, vector <string> & parameters)
catch(lua::exception &e) catch(lua::exception &e)
{ {
con.printerr("Error:%s\n",e.what()); con.printerr("Error:%s\n",e.what());
c->con.printerr("%s",lua::DebugDump(lua::glua::Get()).c_str()); c->con.printerr("%s",lua::DebugDump(lua::glua::Get()).c_str());
} }
s.settop(0);// clean up s.settop(0);// clean up
mymutex->unlock(); mymutex->unlock();

@ -88,25 +88,12 @@ static int lua_Console_lineedit(lua_State *S)
lua::state st(S); lua::state st(S);
DFHack::Console* c=GetConsolePtr(st); DFHack::Console* c=GetConsolePtr(st);
string ret; string ret;
int i=c->lineedit(st.as<string>(1),ret); DFHack::CommandHistory hist;
int i=c->lineedit(st.as<string>(1),ret,hist);
st.push(ret); st.push(ret);
st.push(i); st.push(i);
return 2;// dunno if len is needed... return 2;// dunno if len is needed...
} }
static int lua_Console_history_add(lua_State *S)
{
lua::state st(S);
DFHack::Console* c=GetConsolePtr(st);
c->history_add(st.as<string>(1));
return 0;
}
/*static int lua_Console_history_clear(lua_State *S) //TODO someday add this
{
lua::state st(S);
DFHack::Console* c=GetConsolePtr(st);
c->history_clear();
return 0;
}*/
const luaL_Reg lua_console_func[]= const luaL_Reg lua_console_func[]=
{ {
{"print",lua_Console_print}, {"print",lua_Console_print},
@ -120,8 +107,6 @@ const luaL_Reg lua_console_func[]=
{"get_columns",lua_Console_get_columns}, {"get_columns",lua_Console_get_columns},
{"get_rows",lua_Console_get_rows}, {"get_rows",lua_Console_get_rows},
{"lineedit",lua_Console_lineedit}, {"lineedit",lua_Console_lineedit},
{"history_add",lua_Console_history_add},
//{"history_clear",lua_Console_history_clear},
{NULL,NULL} {NULL,NULL}
}; };
void lua::RegisterConsole(lua::state &st, DFHack::Console *c) void lua::RegisterConsole(lua::state &st, DFHack::Console *c)

@ -140,6 +140,8 @@ public:
}; };
}; };
CommandHistory liquids_hist;
DFhackCExport command_result df_liquids (Core * c, vector <string> & parameters); DFhackCExport command_result df_liquids (Core * c, vector <string> & parameters);
DFhackCExport const char * plugin_name ( void ) DFhackCExport const char * plugin_name ( void )
@ -149,6 +151,7 @@ DFhackCExport const char * plugin_name ( void )
DFhackCExport command_result plugin_init ( Core * c, std::vector <PluginCommand> &commands) DFhackCExport command_result plugin_init ( Core * c, std::vector <PluginCommand> &commands)
{ {
liquids_hist.load("liquids.history");
commands.clear(); commands.clear();
commands.push_back(PluginCommand("liquids", "Place magma, water or obsidian.", df_liquids, true)); commands.push_back(PluginCommand("liquids", "Place magma, water or obsidian.", df_liquids, true));
return CR_OK; return CR_OK;
@ -156,6 +159,7 @@ DFhackCExport command_result plugin_init ( Core * c, std::vector <PluginCommand>
DFhackCExport command_result plugin_shutdown ( Core * c ) DFhackCExport command_result plugin_shutdown ( Core * c )
{ {
liquids_hist.save("liquids.history");
return CR_OK; return CR_OK;
} }
@ -192,7 +196,7 @@ DFhackCExport command_result df_liquids (Core * c, vector <string> & parameters)
string command = ""; string command = "";
std::stringstream str; std::stringstream str;
str <<"[" << mode << ":" << brushname << ":" << amount << ":" << flowmode << ":" << setmode << "]#"; str <<"[" << mode << ":" << brushname << ":" << amount << ":" << flowmode << ":" << setmode << "]#";
if(c->con.lineedit(str.str(),command) == -1) if(c->con.lineedit(str.str(),command,liquids_hist) == -1)
return CR_FAILURE; return CR_FAILURE;
if(command=="help" || command == "?") if(command=="help" || command == "?")
{ {
@ -260,20 +264,24 @@ DFhackCExport command_result df_liquids (Core * c, vector <string> & parameters)
else if(command == "range" || command == "r") else if(command == "range" || command == "r")
{ {
std::stringstream str; std::stringstream str;
CommandHistory range_hist;
str << " :set range width<" << width << "># "; str << " :set range width<" << width << "># ";
c->con.lineedit(str.str(),command); c->con.lineedit(str.str(),command,range_hist);
range_hist.add(command);
width = command == "" ? width : atoi (command.c_str()); width = command == "" ? width : atoi (command.c_str());
if(width < 1) width = 1; if(width < 1) width = 1;
str.clear(); str.clear();
str << " :set range height<" << height << "># "; str << " :set range height<" << height << "># ";
c->con.lineedit(str.str(),command); c->con.lineedit(str.str(),command,range_hist);
range_hist.add(command);
height = command == "" ? height : atoi (command.c_str()); height = command == "" ? height : atoi (command.c_str());
if(height < 1) height = 1; if(height < 1) height = 1;
str.clear(); str.clear();
str << " :set range z-levels<" << z_levels << "># "; str << " :set range z-levels<" << z_levels << "># ";
c->con.lineedit(str.str(),command); c->con.lineedit(str.str(),command,range_hist);
range_hist.add(command);
z_levels = command == "" ? z_levels : atoi (command.c_str()); z_levels = command == "" ? z_levels : atoi (command.c_str());
if(z_levels < 1) z_levels = 1; if(z_levels < 1) z_levels = 1;
delete brush; delete brush;

@ -131,7 +131,8 @@ DFhackCExport command_result mode (Core * c, vector <string> & parameters)
string selected; string selected;
input_again: input_again:
c->con.lineedit("Enter new mode: ",selected); CommandHistory hist;
c->con.lineedit("Enter new mode: ",selected, hist);
if(selected == "c") if(selected == "c")
return CR_OK; return CR_OK;
const char * start = selected.c_str(); const char * start = selected.c_str();

@ -411,6 +411,8 @@ public:
}; };
}; };
CommandHistory tiletypes_hist;
DFhackCExport command_result df_tiletypes (Core * c, vector <string> & parameters); DFhackCExport command_result df_tiletypes (Core * c, vector <string> & parameters);
DFhackCExport const char * plugin_name ( void ) DFhackCExport const char * plugin_name ( void )
@ -420,6 +422,7 @@ DFhackCExport const char * plugin_name ( void )
DFhackCExport command_result plugin_init ( Core * c, std::vector <PluginCommand> &commands) DFhackCExport command_result plugin_init ( Core * c, std::vector <PluginCommand> &commands)
{ {
tiletypes_hist.load("tiletypes.history");
commands.clear(); commands.clear();
commands.push_back(PluginCommand("tiletypes", "Paint map tiles freely, similar to liquids.", df_tiletypes, true)); commands.push_back(PluginCommand("tiletypes", "Paint map tiles freely, similar to liquids.", df_tiletypes, true));
return CR_OK; return CR_OK;
@ -427,6 +430,7 @@ DFhackCExport command_result plugin_init ( Core * c, std::vector <PluginCommand>
DFhackCExport command_result plugin_shutdown ( Core * c ) DFhackCExport command_result plugin_shutdown ( Core * c )
{ {
tiletypes_hist.save("tiletypes.history");
return CR_OK; return CR_OK;
} }
@ -455,7 +459,8 @@ DFhackCExport command_result df_tiletypes (Core * c, vector <string> & parameter
std::string option = ""; std::string option = "";
std::string value = ""; std::string value = "";
c->con.lineedit("tiletypes> ",input); c->con.lineedit("tiletypes> ",input,tiletypes_hist);
tiletypes_hist.add(input);
std::istringstream ss(input); std::istringstream ss(input);
ss >> command >> option >> value; ss >> command >> option >> value;
tolower(command); tolower(command);
@ -486,20 +491,21 @@ DFhackCExport command_result df_tiletypes (Core * c, vector <string> & parameter
else if (command == "range" || command == "r") else if (command == "range" || command == "r")
{ {
std::stringstream ss; std::stringstream ss;
CommandHistory hist;
ss << "Set range width <" << width << "> "; ss << "Set range width <" << width << "> ";
c->con.lineedit(ss.str(),command); c->con.lineedit(ss.str(),command,hist);
width = command == "" ? width : toint(command); width = command == "" ? width : toint(command);
if (width < 1) width = 1; if (width < 1) width = 1;
ss.str(""); ss.str("");
ss << "Set range height <" << height << "> "; ss << "Set range height <" << height << "> ";
c->con.lineedit(ss.str(),command); c->con.lineedit(ss.str(),command,hist);
height = command == "" ? height : toint(command); height = command == "" ? height : toint(command);
if (height < 1) height = 1; if (height < 1) height = 1;
ss.str(""); ss.str("");
ss << "Set range z-levels <" << z_levels << "> "; ss << "Set range z-levels <" << z_levels << "> ";
c->con.lineedit(ss.str(),command); c->con.lineedit(ss.str(),command,hist);
z_levels = command == "" ? z_levels : toint(command); z_levels = command == "" ? z_levels : toint(command);
if (z_levels < 1) z_levels = 1; if (z_levels < 1) z_levels = 1;

@ -23,10 +23,7 @@ DFhackCExport const char * plugin_name ( void )
DFhackCExport command_result plugin_init ( Core * c, std::vector <PluginCommand> &commands) DFhackCExport command_result plugin_init ( Core * c, std::vector <PluginCommand> &commands)
{ {
commands.clear(); commands.clear();
commands.push_back(PluginCommand("weather", commands.push_back(PluginCommand("weather", "Print the weather map or change weather.",weather));
"Print the weather map or change weather.\
\n Options: 'snow' = make it snow, 'rain' = make it rain.\
\n 'clear' = clear the sky",weather));
return CR_OK; return CR_OK;
} }
@ -61,7 +58,13 @@ DFhackCExport command_result weather (Core * c, vector <string> & parameters)
} }
if(help) if(help)
{ {
c->con.print("Prints the current weather map by default.\n"
"Options:\n"
"snow - make it snow everywhere.\n"
"rain - make it rain.\n"
"clear - clear the sky.\n"
);
return CR_OK;
} }
if(lock && unlock) if(lock && unlock)
{ {