1 #include "Getline.h"
2 
3 std::vector<std::string> inputLines;
4 std::string homeDir;
5 
save_session(const std::string & path)6 void save_session(const std::string& path)
7 {
8 	std::ofstream ofs(path);
9 
10 	for(size_t l=0; l<inputLines.size(); l++)
11 		ofs << inputLines[l] << std::endl;
12 
13 	ofs.close();
14 }
15 
write_prompt(const std::string & lang,const std::string & pwd,const std::string & promptCh)16 void write_prompt(const std::string& lang, const std::string& pwd, const std::string& promptCh)
17 {
18 	//clears current line in console
19 	clear_console_line();
20 	if(lang != "")
21 	{
22 		std::cout << c_green << lang << c_white;
23 		if(pwd != "")
24 			std::cout << ":";
25 	}
26 	if(pwd != "")
27 		std::cout << c_purple << pwd << c_white;
28 	if(lang != "" || pwd != "")
29 		std::cout << promptCh << " ";
30 }
31 
write_input_line(const std::string & lang,const std::string & pwd,const std::string & promptCh,const std::string & str,size_t & sPos,const size_t & usableLength,const size_t & linePos,const size_t & bLinePos)32 void write_input_line(const std::string& lang,
33 	            const std::string& pwd,
34                 const std::string& promptCh,
35 	            const std::string& str,
36 	            size_t& sPos,
37 	            const size_t& usableLength,
38 				const size_t& linePos,
39 				const size_t& bLinePos)
40 {
41 	write_prompt(lang, pwd, promptCh);
42 
43 	if(sPos + usableLength >= linePos)
44 	{
45 		if(str.size()-sPos <= usableLength)
46 		{
47 			std::cout << str.substr(sPos, str.size()-sPos);
48 
49 			size_t ePos = 0;
50 			for(size_t i=ePos; i<bLinePos; i++)
51 				std::cout << "\b";
52 		}
53 		else
54 		{
55 			std::cout << str.substr(sPos, usableLength);
56 
57 			size_t ePos = str.size() - sPos - usableLength;
58 			for(size_t i=ePos; i<bLinePos; i++)
59 				std::cout << "\b";
60 		}
61 	}
62 	else
63 	{
64 		sPos = str.size() - usableLength;
65 		std::cout << str.substr(sPos, usableLength);
66 
67 		size_t ePos = 0;
68 		for(size_t i=ePos; i<bLinePos; i++)
69 			std::cout << "\b";
70 	}
71 
72 	//std::cout << std::flush;
73 	std::fflush(stdout);
74 }
75 
nsm_getch()76 int nsm_getch()
77 {
78 	char c;
79 
80 	#if defined _WIN32 || defined _WIN64
81 		c = _getch();
82 	#else
83 		enable_raw_mode();
84 		c = getchar();
85 		disable_raw_mode();
86 	#endif
87 
88 	return c;
89 }
90 
rnbwcout(const std::string & str)91 int rnbwcout(const std::string& str)
92 {
93 	std::stringstream ss;
94 	ss << str << std::endl;
95 
96 	return lolfilter(ss);
97 }
98 
rnbwcout(const std::set<std::string> & strs)99 int rnbwcout(const std::set<std::string>& strs)
100 {
101 	std::stringstream ss;
102 	if(strs.size())
103 	{
104 		auto str=strs.begin();
105 		ss << *str++;
106 		for(; str!=strs.end(); ++str)
107 			ss << " " << *str;
108 		ss << std::endl;
109 	}
110 
111 	return lolfilter(ss);
112 }
113 
114 #if defined _WIN32 || defined _WIN64
getline(const std::string & lang,const bool & addPwd,const std::string & promptCh,const int & lolcatActive,std::string & str,bool trackLines,const std::vector<std::string> & tabCompletionStrs)115 	int getline(const std::string& lang,
116 	            const bool& addPwd,
117 	            const std::string& promptCh,
118 	            const int& lolcatActive,
119 	            std::string& str,
120 	            bool trackLines,
121 	            const std::vector<std::string>& tabCompletionStrs)
122 	{
123 		char c;
124 		std::string pwd;
125 		size_t promptLength = 0, usableLength;
126 		int prevConsoleWidth = 100000, currConsoleWidth;
127 
128 		size_t cLine = inputLines.size();
129 		std::string backupStr;
130 
131 		size_t bLinePos = 0, linePos = str.size(); //line position of insertion
132 		size_t sPos = 0;
133 
134 		if(!addPwd)
135 		{
136 			promptLength = lang.size() + 2;
137 		}
138 
139 		while(1)
140 		{
141 			currConsoleWidth = console_width();
142 			if(currConsoleWidth != prevConsoleWidth)
143 			{
144 				prevConsoleWidth = currConsoleWidth;
145 				if(addPwd)
146 				{
147 					pwd = get_pwd();
148 					homeDir = home_dir();
149 					if(homeDir != "" && homeDir == pwd.substr(0, homeDir.size()))
150 						pwd = "~" + pwd.substr(homeDir.size(), pwd.size()-homeDir.size());
151 
152 					const int MIN_USABLE_LENGTH = currConsoleWidth/2;
153 					size_t maxPWDLength = std::max(0, (int)currConsoleWidth - (int)lang.size() - 3 - 1 - 2 - MIN_USABLE_LENGTH);
154 					if(pwd.size() > maxPWDLength)
155 						pwd = ".." + pwd.substr(pwd.size()-maxPWDLength, maxPWDLength);
156 
157 					promptLength = lang.size() + pwd.size() + promptCh.size() + 2;
158 				}
159 			}
160 			usableLength = std::max(0, (int)currConsoleWidth - (int)promptLength - 1);
161 
162 			write_input_line(lang, pwd, promptCh, str, sPos, usableLength, linePos, bLinePos);
163 
164 			c = _getch();
165 
166 			if(c == '\r' || c == '\n' || c == 10) //new line
167 			{
168 				write_prompt(lang, pwd, promptCh);
169 				if(str.size() && str[str.size()-1] == '\\')
170 					std::cout << str.substr(0, str.size()-1) << std::endl;
171 				else
172 					std::cout << str << std::endl;
173 
174 				if(trackLines)
175 					if(!inputLines.size() || str != inputLines[inputLines.size()-1])
176 						inputLines.push_back(str);
177 
178 				if(c == 10) // ctrl enter
179 					return NSM_SENTER;
180 				else
181 					return 0;
182 			}
183 			else if(c == '\t') //tab completion
184 			{
185 				std::vector<int> searchPosVec, trimPosVec;
186 				bool foundCompletions = 0;
187 
188 				int searchPos = linePos-1,
189 				    trimPos = -1;
190 
191 				for(; searchPos >= 0 &&
192 				      str[searchPos] != '\n'; --searchPos)
193 				{
194 					if(str[searchPos] == ' ' ||
195 						str[searchPos] == '\t' ||
196 						str[searchPos] == '"' ||
197 						str[searchPos] == '\'' ||
198 						str[searchPos] == '`' ||
199 						str[searchPos] == '(' ||
200 						str[searchPos] == '[' ||
201 						str[searchPos] == '<' ||
202 						str[searchPos] == '{' ||
203 						str[searchPos] == ',')
204 					{
205 						if(searchPos+1<(int)str.size() && str[searchPos] == ' ' && str[searchPos+1] == ' ')
206 							continue;
207 
208 						searchPosVec.push_back(searchPos + 1);
209 						if(trimPos == -1)
210 							trimPosVec.push_back(searchPos + 1);
211 						else
212 							trimPosVec.push_back(trimPos);
213 					}
214 					if(searchPos && (str[searchPos] == '/' || str[searchPos] == '\\') && trimPos == -1)
215 						trimPos = searchPos+1;
216 				}
217 				if(str[searchPos+1] != ' ')
218 				{
219 					searchPosVec.push_back(searchPos + 1);
220 					if(trimPos == -1)
221 						trimPosVec.push_back(searchPos + 1);
222 					else
223 						trimPosVec.push_back(trimPos);
224 				}
225 
226 				for(int i=searchPosVec.size()-1; i>=0; --i)
227 				{
228 					searchPos = searchPosVec[i];
229 					trimPos = trimPosVec[i];
230 
231 					Path tabPath;
232 					std::set<std::string> paths, programs;
233 					std::string searchStr = str.substr(searchPos, linePos-searchPos);
234 					strip_leading_whitespace(searchStr);
235 					if(searchStr != "")
236 					{
237 						tabPath.set_file_path_from(searchStr.c_str());
238 						makeSearchable(tabPath);
239 						paths = lsSetStar(tabPath, -1);
240 					}
241 
242 					if(paths.size())
243 					{
244 						foundCompletions = 1;
245 
246 						auto path = paths.begin();
247 						std::string foundStr = *path;
248 						++path;
249 						for(; path!=paths.end(); ++path)
250 						{
251 							int pMax = std::min(foundStr.size(), path->size()),
252 							    pos = 0;
253 							for(; pos < pMax; ++pos)
254 							{
255 								if(foundStr[pos] != (*path)[pos])
256 									break;
257 							}
258 							foundStr = foundStr.substr(0, pos);
259 						}
260 
261 						if(linePos-trimPos < foundStr.size())
262 							foundStr = foundStr.substr(linePos-trimPos, foundStr.size()-linePos+trimPos);
263 						else
264 							foundStr = "";
265 
266 						if(foundStr == "" && paths.size() != 1)
267 						{
268 							std::cout << "\n";
269 							if(lolcatActive)
270 								rnbwcout(paths);
271 							else
272 							{
273 								coutPaths(tabPath.dir, paths, " ", 1, 20);
274 								std::cout << std::endl;
275 							}
276 						}
277 						else
278 						{
279 							if(paths.size() == 1)
280 							{
281 								if(!foundStr.size() || (foundStr[foundStr.size()-1] != '/' && foundStr[foundStr.size()-1] != '\\'))
282 								{
283 									//add close quote if tab completion started with a quote and not a directory
284 									if(searchPos > 0 && str[searchPos-1] == '"')
285 										foundStr += "\"";
286 									if(searchPos > 0 && str[searchPos-1] == '\'')
287 										foundStr += "'";
288 
289 									//foundStr += " ";
290 								}
291 							}
292 
293 							if(foundStr == "")
294 								std::cout << "\a" << std::flush;
295 							else
296 							{
297 								str = str.substr(0, linePos) + foundStr + str.substr(linePos, str.size()-linePos);
298 
299 								for(size_t i=0; i<foundStr.size(); i++)
300 								{
301 									++linePos;
302 									if(sPos + usableLength +1 == linePos)
303 										++sPos;
304 								}
305 							}
306 						}
307 
308 						break;
309 					}
310 
311 					if(searchStr != "")
312 					{
313 						for(size_t j=0; j<tabCompletionStrs.size(); ++j)
314 						{
315 							if(searchStr == tabCompletionStrs[j].substr(0, searchStr.size()))
316 								programs.insert(tabCompletionStrs[j]);
317 						}
318 					}
319 
320 					if(programs.size())
321 					{
322 						foundCompletions = 1;
323 
324 						if(programs.size() != 1)
325 						{
326 							std::cout << "\n";
327 							if(lolcatActive)
328 								rnbwcout(programs);
329 							else
330 							{
331 								coutPaths("", programs, " ", 0, 20);
332 								std::cout << std::endl;
333 							}
334 						}
335 						else
336 						{
337 							std::string foundStr = *programs.begin();
338 							foundStr = foundStr.substr(searchStr.size(), foundStr.size() - searchStr.size());
339 							//if(!foundStr.size() || (foundStr[foundStr.size()-1] != '/' && foundStr[foundStr.size()-1] != '\\'))
340 							//	foundStr += " ";
341 
342 							if(foundStr == "")
343 								std::cout << "\a" << std::flush;
344 							else
345 							{
346 								str = str.substr(0, linePos) + foundStr + str.substr(linePos, str.size()-linePos);
347 
348 								for(size_t i=0; i<foundStr.size(); i++)
349 								{
350 									++linePos;
351 									if(sPos + usableLength +1 == linePos)
352 										++sPos;
353 								}
354 							}
355 						}
356 						break;
357 					}
358 				}
359 
360 				if(!foundCompletions)
361 				{
362 					for(int i=0; i<2; i++)
363 					{
364 						str = str.substr(0, linePos) + " " + str.substr(linePos, str.size()-linePos);
365 						++linePos;
366 
367 						if(sPos + usableLength + 1 == linePos)
368 							++sPos;
369 					}
370 				}
371 			}
372 			else if(c == 1) //ctrl a
373 			{
374 				bLinePos = str.size(); //line position of insertion
375 				linePos = sPos = 0;
376 			}
377 			else if(c == 2) //ctrl b
378 			{
379 				if(linePos > 0)
380 				{
381 					--linePos;
382 					++bLinePos;
383 
384 					if(linePos < sPos)
385 						sPos = linePos;
386 				}
387 			}
388 			else if(c == 3 || c == 26) //ctrl c & ctrl z
389 			{
390 				//clear_console_line();
391 				std::cout << std::endl << c_red << "--terminated by user--" << c_white << std::endl;
392 
393 				return NSM_KILL;
394 			}
395 			else if(c == 4) //ctrl d
396 			{
397 				str = str.substr(0, linePos);
398 				bLinePos = 0;
399 			}
400 			else if(c == 5) //ctrl e
401 			{
402 				bLinePos = sPos = 0;
403 				linePos = str.size();
404 			}
405 			else if(c == 6) //ctrl f
406 			{
407 				if(bLinePos > 0)
408 				{
409 					++linePos;
410 					--bLinePos;
411 
412 					if(sPos + usableLength == linePos)
413 						++sPos;
414 				}
415 			}
416 			else if(c == 8) //backspace
417 			{
418 				if(linePos > 0)
419 				{
420 					str = str.substr(0, linePos-1) + str.substr(linePos, str.size()-linePos);
421 					--linePos;
422 
423 					if(sPos > 0 && str.size() - sPos < usableLength)
424 						--sPos;
425 				}
426 			}
427 			else if(c == 27 || c == 127) //ctrl [ or ctrl backspace
428 			{
429 				bool foundNonWhitespace = 0;
430 				do
431 				{
432 					if(linePos > 0)
433 					{
434 						if(str[linePos-1] != ' ' && str[linePos-1] != '\t')
435 							foundNonWhitespace = 1;
436 
437 						str = str.substr(0, linePos-1) + str.substr(linePos, str.size()-linePos);
438 						--linePos;
439 
440 						if(sPos > 0 && str.size() - sPos < usableLength)
441 							--sPos;
442 					}
443 					else
444 						break;
445 				}while(!foundNonWhitespace || (linePos > 0 && std::isalnum(str[linePos-1])));
446 			}
447 			else if(c == 29) //ctrl ]
448 			{
449 				bool foundNonWhitespace = 0;
450 				char c = 'a';
451 
452 				while(!foundNonWhitespace || std::isalnum(c))
453 				{
454 					if(bLinePos > 0)
455 					{
456 						c = str[linePos];
457 
458 						if(c != ' ' && c != '\t')
459 							foundNonWhitespace = 1;
460 
461 						str = str.substr(0, linePos) + str.substr(linePos + 1, str.size()-linePos+1);
462 						--bLinePos;
463 
464 						if(sPos + usableLength == linePos)
465 							++sPos;
466 					}
467 					else
468 						break;
469 				}
470 			}
471 			else if(c == 18) //ctrl+r (same as opt/alt+enter)
472 			{
473 				write_prompt(lang, pwd, promptCh);
474 				std::cout << str << std::endl;
475 
476 				if(trackLines)
477 					if(!inputLines.size() || str != inputLines[inputLines.size()-1])
478 						inputLines.push_back(str);
479 
480 				return NSM_SENTER;
481 			}
482 			else if(c == 0 || c == -32) //check for arrow keys
483 			{
484 				c = _getch();
485 
486 				if(c == -108) //ctrl+tab
487 				{
488 					//std::cout << "\a" << std::flush;
489 
490 					for(int i=0; i<2; i++)
491 					{
492 						str = str.substr(0, linePos) + " " + str.substr(linePos, str.size()-linePos);
493 						++linePos;
494 
495 						if(sPos + usableLength + 1 == linePos)
496 							++sPos;
497 					}
498 				}
499 
500 				if(c == -115) //ctrl up arrow
501 				{
502 				}
503 				else if(c == -111) //ctrl down arrow
504 				{
505 				}
506 				else if(c == 116) //ctrl right arrow
507 				{
508 					do
509 					{
510 						if(bLinePos > 0)
511 						{
512 							++linePos;
513 							--bLinePos;
514 
515 							if(sPos + usableLength == linePos)
516 								++sPos;
517 						}
518 					}while(bLinePos > 0 && std::isalnum(str[linePos]));
519 				}
520 				else if(c == 115) //ctrl left arrow
521 				{
522 					do
523 					{
524 						if(linePos > 0)
525 						{
526 							--linePos;
527 							++bLinePos;
528 
529 							if(linePos < sPos)
530 								sPos = linePos;
531 						}
532 					}while(linePos > 0 && std::isalnum(str[linePos]));
533 				}
534 
535 				else if(c == 72) //up arrow
536 				{
537 					if(cLine > 0)
538 					{
539 						if(cLine == inputLines.size())
540 							backupStr = str;
541 						--cLine;
542 						str = inputLines[cLine];
543 						bLinePos = sPos = 0;
544 						linePos = str.size();
545 					}
546 				}
547 				else if(c == 80) //down arrow
548 				{
549 					if(cLine < inputLines.size())
550 					{
551 						++cLine;
552 						if(cLine == inputLines.size())
553 							str = backupStr;
554 						else
555 							str = inputLines[cLine];
556 						bLinePos = sPos = 0;
557 						linePos = str.size();
558 					}
559 				}
560 				else if(c == 77) //right arrow
561 				{
562 					if(bLinePos > 0)
563 					{
564 						++linePos;
565 						--bLinePos;
566 
567 						if(sPos + usableLength == linePos)
568 							++sPos;
569 					}
570 				}
571 				else if(c == 75) //left arrow
572 				{
573 					if(linePos > 0)
574 					{
575 						--linePos;
576 						++bLinePos;
577 
578 						if(linePos < sPos)
579 							sPos = linePos;
580 					}
581 				}
582 			}
583 			else
584 			{
585 				str = str.substr(0, linePos) + c + str.substr(linePos, str.size()-linePos);
586 				++linePos;
587 
588 				if(sPos + usableLength +1 == linePos)
589 					++sPos;
590 			}
591 
592 			write_input_line(lang, pwd, promptCh, str, sPos, usableLength, linePos, bLinePos);
593 		}
594 
595 		return 0;
596 	}
597 #else  //*nix
getline(const std::string & lang,const bool & addPwd,const std::string & promptCh,const int & lolcatActive,std::string & str,bool trackLines,const std::vector<std::string> & tabCompletionStrs)598 	int getline(const std::string& lang,
599 	            const bool& addPwd,
600 	            const std::string& promptCh,
601 	            const int& lolcatActive,
602 	            std::string& str,
603 	            bool trackLines,
604 	            const std::vector<std::string>& tabCompletionStrs)
605 	{
606 		char c;
607 		std::string pwd;
608 		size_t promptLength = 0, usableLength;
609 		int prevConsoleWidth = 100000, currConsoleWidth;
610 
611 		size_t cLine = inputLines.size();
612 		std::string backupStr;
613 
614 		size_t bLinePos = 0, linePos = str.size(); //line position of insertion
615 		size_t sPos = 0;
616 
617 		if(!addPwd)
618 		{
619 			promptLength = lang.size() + 2;
620 		}
621 
622 		enable_raw_mode();
623 		while(1)
624 		{
625 			currConsoleWidth = console_width();
626 			if(currConsoleWidth != prevConsoleWidth)
627 			{
628 				prevConsoleWidth = currConsoleWidth;
629 				if(addPwd)
630 				{
631 					pwd = get_pwd();
632 					homeDir = home_dir();
633 					if(homeDir != "" && homeDir == pwd.substr(0, homeDir.size()))
634 						pwd = "~" + pwd.substr(homeDir.size(), pwd.size()-homeDir.size());
635 					#if defined __FreeBSD__
636 						else
637 						{
638 							homeDir = "/usr" + homeDir;
639 							if(homeDir != "" && homeDir == pwd.substr(0, homeDir.size()))
640 								pwd = "~" + pwd.substr(homeDir.size(), pwd.size()-homeDir.size());
641 						}
642 					#endif
643 
644 					const int MIN_USABLE_LENGTH = currConsoleWidth/2;
645 					size_t maxPWDLength = std::max(0, (int)currConsoleWidth - (int)lang.size() - 3 - 1 - 2 - MIN_USABLE_LENGTH);
646 					if(pwd.size() > maxPWDLength)
647 						pwd = ".." + pwd.substr(pwd.size()-maxPWDLength, maxPWDLength);
648 
649 					promptLength = lang.size() + pwd.size() + promptCh.size() + 2;
650 				}
651 			}
652 			usableLength = std::max(0, (int)currConsoleWidth - (int)promptLength - 1);
653 
654 			write_input_line(lang, pwd, promptCh, str, sPos, usableLength, linePos, bLinePos);
655 
656 			c = getchar();
657 
658 			if(c == '\r' || c == '\n') //new line
659 			{
660 				write_prompt(lang, pwd, promptCh);
661 				if(str.size() && str[str.size()-1] == '\\')
662 					std::cout << str.substr(0, str.size()-1) << std::endl;
663 				else
664 					std::cout << str << std::endl;
665 
666 				if(trackLines)
667 					if(!inputLines.size() || str != inputLines[inputLines.size()-1])
668 						inputLines.push_back(str);
669 				disable_raw_mode(); //system("stty cooked");
670 				return 0;
671 			}
672 			else if(c == '\t') //tab completion
673 			{
674 				std::vector<int> searchPosVec, trimPosVec;
675 				bool foundCompletions = 0;
676 
677 				int searchPos = linePos-1,
678 				    trimPos = -1;
679 
680 				for(; searchPos >= 0 &&
681 				      str[searchPos] != '\n'; --searchPos)
682 				{
683 					if(str[searchPos] == ' ' ||
684 						str[searchPos] == '\t' ||
685 						str[searchPos] == '"' ||
686 						str[searchPos] == '\'' ||
687 						str[searchPos] == '`' ||
688 						str[searchPos] == '(' ||
689 						str[searchPos] == '[' ||
690 						str[searchPos] == '<' ||
691 						str[searchPos] == '{' ||
692 						str[searchPos] == ',')
693 					{
694 						if(searchPos+1<(int)str.size() && str[searchPos] == ' ' && str[searchPos+1] == ' ')
695 							continue;
696 
697 						searchPosVec.push_back(searchPos + 1);
698 						if(trimPos == -1)
699 							trimPosVec.push_back(searchPos + 1);
700 						else
701 							trimPosVec.push_back(trimPos);
702 					}
703 					if(searchPos && (str[searchPos] == '/' || str[searchPos] == '\\') && trimPos == -1)
704 						trimPos = searchPos+1;
705 				}
706 				if(str[searchPos+1] != ' ')
707 				{
708 					searchPosVec.push_back(searchPos + 1);
709 					if(trimPos == -1)
710 						trimPosVec.push_back(searchPos + 1);
711 					else
712 						trimPosVec.push_back(trimPos);
713 				}
714 
715 				for(int i=searchPosVec.size()-1; i>=0; --i)
716 				{
717 					searchPos = searchPosVec[i];
718 					trimPos = trimPosVec[i];
719 
720 					Path tabPath;
721 					std::set<std::string> paths, programs;
722 					std::string searchStr = str.substr(searchPos, linePos-searchPos);
723 					strip_leading_whitespace(searchStr);
724 					if(searchStr != "")
725 					{
726 						tabPath.set_file_path_from(searchStr.c_str());
727 						makeSearchable(tabPath);
728 						paths = lsSetStar(tabPath, -1);
729 					}
730 
731 					if(paths.size())
732 					{
733 						foundCompletions = 1;
734 
735 						auto path = paths.begin();
736 						std::string foundStr = *path;
737 						++path;
738 						for(; path!=paths.end(); ++path)
739 						{
740 							int pMax = std::min(foundStr.size(), path->size()),
741 							    pos = 0;
742 							for(; pos < pMax; ++pos)
743 							{
744 								if(foundStr[pos] != (*path)[pos])
745 									break;
746 							}
747 							foundStr = foundStr.substr(0, pos);
748 						}
749 
750 						if(linePos-trimPos < foundStr.size())
751 							foundStr = foundStr.substr(linePos-trimPos, foundStr.size()-linePos+trimPos);
752 						else
753 							foundStr = "";
754 
755 						if(foundStr == "" && paths.size() != 1)
756 						{
757 							std::cout << "\n";
758 							if(lolcatActive)
759 								rnbwcout(paths);
760 							else
761 							{
762 								coutPaths(tabPath.dir, paths, " ", 1, 20);
763 								std::cout << std::endl;
764 							}
765 						}
766 						else
767 						{
768 							if(paths.size() == 1)
769 							{
770 								if(!foundStr.size() || (foundStr[foundStr.size()-1] != '/' && foundStr[foundStr.size()-1] != '\\'))
771 								{
772 									//add close quote if tab completion started with a quote and not a directory
773 									if(searchPos > 0 && str[searchPos-1] == '"')
774 										foundStr += "\"";
775 									if(searchPos > 0 && str[searchPos-1] == '\'')
776 										foundStr += "'";
777 
778 									//foundStr += " ";
779 								}
780 							}
781 
782 							if(foundStr == "")
783 								std::cout << "\a" << std::flush;
784 							else
785 							{
786 								str = str.substr(0, linePos) + foundStr + str.substr(linePos, str.size()-linePos);
787 
788 								for(size_t i=0; i<foundStr.size(); i++)
789 								{
790 									++linePos;
791 									if(sPos + usableLength +1 == linePos)
792 										++sPos;
793 								}
794 							}
795 						}
796 
797 						break;
798 					}
799 
800 					if(searchStr != "")
801 					{
802 						for(size_t j=0; j<tabCompletionStrs.size(); ++j)
803 						{
804 							if(searchStr == tabCompletionStrs[j].substr(0, searchStr.size()))
805 								programs.insert(tabCompletionStrs[j]);
806 						}
807 					}
808 
809 					if(programs.size())
810 					{
811 						foundCompletions = 1;
812 
813 						if(programs.size() != 1)
814 						{
815 							std::cout << "\n";
816 							if(lolcatActive)
817 								rnbwcout(programs);
818 							else
819 							{
820 								coutPaths("", programs, " ", 0, 20);
821 								std::cout << std::endl;
822 							}
823 						}
824 						else
825 						{
826 							std::string foundStr = *programs.begin();
827 							foundStr = foundStr.substr(searchStr.size(), foundStr.size() - searchStr.size());
828 							//if(!foundStr.size() || (foundStr[foundStr.size()-1] != '/' && foundStr[foundStr.size()-1] != '\\'))
829 							//	foundStr += " ";
830 
831 							if(foundStr == "")
832 								std::cout << "\a" << std::flush;
833 							else
834 							{
835 								str = str.substr(0, linePos) + foundStr + str.substr(linePos, str.size()-linePos);
836 
837 								for(size_t i=0; i<foundStr.size(); i++)
838 								{
839 									++linePos;
840 									if(sPos + usableLength +1 == linePos)
841 										++sPos;
842 								}
843 							}
844 						}
845 						break;
846 					}
847 				}
848 
849 				if(!foundCompletions)
850 				{
851 					for(int i=0; i<2; i++)
852 					{
853 						str = str.substr(0, linePos) + " " + str.substr(linePos, str.size()-linePos);
854 						++linePos;
855 
856 						if(sPos + usableLength + 1 == linePos)
857 							++sPos;
858 					}
859 				}
860 			}
861 			else if(c == 1) //ctrl a
862 			{
863 				bLinePos = str.size(); //line position of insertion
864 				linePos = sPos = 0;
865 			}
866 			else if(c == 2) //ctrl b
867 			{
868 				if(linePos > 0)
869 				{
870 					--linePos;
871 					++bLinePos;
872 
873 					if(linePos < sPos)
874 						sPos = linePos;
875 				}
876 			}
877 			else if(c == 4) //ctrl d
878 			{
879 				str = str.substr(0, linePos);
880 				bLinePos = 0;
881 			}
882 			else if(c == 5) //ctrl e
883 			{
884 				bLinePos = sPos = 0;
885 				linePos = str.size();
886 			}
887 			else if(c == 6) //ctrl f
888 			{
889 				if(bLinePos > 0)
890 				{
891 					++linePos;
892 					--bLinePos;
893 
894 					if(sPos + usableLength == linePos)
895 						++sPos;
896 				}
897 			}
898 			#if defined __FreeBSD__
899 				else if(c == 127 || c == 31) //ctrl backspace or cmd [ or ctrl (shift) -
900 			#else  //unix
901 				else if(c == 8 || c == 31) //ctrl backspace or cmd [ or ctrl (shift) -
902 			#endif
903 			{
904 				bool foundNonWhitespace = 0;
905 				do
906 				{
907 					if(linePos > 0)
908 					{
909 						if(str[linePos-1] != ' ' && str[linePos-1] != '\t')
910 							foundNonWhitespace = 1;
911 
912 						str = str.substr(0, linePos-1) + str.substr(linePos, str.size()-linePos);
913 						--linePos;
914 
915 						if(sPos > 0 && str.size() - sPos < usableLength)
916 							--sPos;
917 					}
918 					else
919 						break;
920 				}while(!foundNonWhitespace || (linePos > 0 && std::isalnum(str[linePos-1])));
921 			}
922 			else if(c == 29) //ctrl ]
923 			{
924 				bool foundNonWhitespace = 0;
925 				char c = 'a';
926 
927 				while(!foundNonWhitespace || std::isalnum(c))
928 				{
929 					if(bLinePos > 0)
930 					{
931 						c = str[linePos];
932 
933 						if(c != ' ' && c != '\t')
934 							foundNonWhitespace = 1;
935 
936 						str = str.substr(0, linePos) + str.substr(linePos + 1, str.size()-linePos+1);
937 						--bLinePos;
938 
939 						if(sPos + usableLength == linePos)
940 							++sPos;
941 					}
942 					else
943 						break;
944 				}
945 			}
946 			#if defined __FreeBSD__
947 				else if(c == 8) //backspace
948 			#else  //unix
949 				else if(c == 127) //backspace
950 			#endif
951 			{
952 				if(linePos > 0)
953 				{
954 					str = str.substr(0, linePos-1) + str.substr(linePos, str.size()-linePos);
955 					--linePos;
956 
957 					if(sPos > 0 && str.size() - sPos < usableLength)
958 						--sPos;
959 				}
960 			}
961 			else if(c == 18) //ctrl+r (same as opt/alt+enter)
962 			{
963 				write_prompt(lang, pwd, promptCh);
964 				std::cout << str << std::endl;
965 
966 				if(trackLines)
967 					if(!inputLines.size() || str != inputLines[inputLines.size()-1])
968 						inputLines.push_back(str);
969 				disable_raw_mode(); //system("stty cooked");
970 
971 				return NSM_SENTER;
972 			}
973 			else if(c == '\33' || c == 27) //check for arrow keys
974 			{
975 				c = getchar();
976 
977 				if(c == 10) //option/alt + enter
978 				{
979 					write_prompt(lang, pwd, promptCh);
980 					std::cout << str << std::endl;
981 
982 					if(trackLines)
983 						if(!inputLines.size() || str != inputLines[inputLines.size()-1])
984 							inputLines.push_back(str);
985 					disable_raw_mode(); //system("stty cooked");
986 
987 					return NSM_SENTER;
988 				}
989 				else if(c == 91)
990 				{
991 					c = getchar();
992 
993 					if(c == 49)
994 					{
995 						c = getchar();
996 
997 						if(c == 59)
998 						{
999 							c = getchar();
1000 
1001 							if(c == 51 || c == 53) //alt or ctrl
1002 							{
1003 								c = getchar();
1004 
1005 								if(c == 65) //alt+up and ctrl+up
1006 								{
1007 								}
1008 								else if(c == 66) //alt+down and ctrl+down
1009 								{
1010 								}
1011 								else if(c == 67) //alt+right and ctrl+right
1012 								{
1013 									do
1014 									{
1015 										if(bLinePos > 0)
1016 										{
1017 											++linePos;
1018 											--bLinePos;
1019 
1020 											if(sPos + usableLength == linePos)
1021 												++sPos;
1022 										}
1023 									}while(bLinePos > 0 && std::isalnum(str[linePos]));
1024 								}
1025 								else if(c == 68) //alt+left and ctrl+left
1026 								{
1027 									do
1028 									{
1029 										if(linePos > 0)
1030 										{
1031 											--linePos;
1032 											++bLinePos;
1033 
1034 											if(linePos < sPos)
1035 												sPos = linePos;
1036 										}
1037 									}while(linePos > 0 && std::isalnum(str[linePos]));
1038 								}
1039 							}
1040 						}
1041 					}
1042 					else if(c == 65) //up arrow
1043 					{
1044 						if(cLine > 0)
1045 						{
1046 							if(cLine == inputLines.size())
1047 								backupStr = str;
1048 							--cLine;
1049 							str = inputLines[cLine];
1050 							bLinePos = sPos = 0;
1051 							linePos = str.size();
1052 						}
1053 					}
1054 					else if(c == 66) //down arrow
1055 					{
1056 						if(cLine < inputLines.size())
1057 						{
1058 							++cLine;
1059 							if(cLine == inputLines.size())
1060 								str = backupStr;
1061 							else
1062 								str = inputLines[cLine];
1063 							bLinePos = sPos = 0;
1064 							linePos = str.size();
1065 						}
1066 					}
1067 					else if(c == 67) //right arrow
1068 					{
1069 						if(bLinePos > 0)
1070 						{
1071 							++linePos;
1072 							--bLinePos;
1073 
1074 							if(sPos + usableLength == linePos)
1075 								++sPos;
1076 						}
1077 					}
1078 					else if(c == 68) //left arrow
1079 					{
1080 						if(linePos > 0)
1081 						{
1082 							--linePos;
1083 							++bLinePos;
1084 
1085 							if(linePos < sPos)
1086 								sPos = linePos;
1087 						}
1088 					}
1089 					else if(c == 90) //shift tab
1090 						std::cout << "\a" << std::flush;
1091 				}
1092 				#if defined __APPLE__
1093 					else if(c == 91)
1094 					{
1095 						c = getchar();
1096 
1097 						if(c == 65) //opt+up
1098 						{}
1099 						else if(c == 66) //opt+down
1100 						{}
1101 					}
1102 					else if(c == 98) //opt+left
1103 					{
1104 						do
1105 						{
1106 							if(linePos > 0)
1107 							{
1108 								--linePos;
1109 								++bLinePos;
1110 
1111 								if(linePos < sPos)
1112 									sPos = linePos;
1113 							}
1114 						}while(linePos > 0 && std::isalnum(str[linePos]));
1115 					}
1116 					else if(c == 102) //opt+right
1117 					{
1118 						do
1119 						{
1120 							if(bLinePos > 0)
1121 							{
1122 								++linePos;
1123 								--bLinePos;
1124 
1125 								if(sPos + usableLength == linePos)
1126 									++sPos;
1127 							}
1128 						}while(bLinePos > 0 && std::isalnum(str[linePos]));
1129 					}
1130 				#endif
1131 				else if(c == 98) //alt b
1132 				{
1133 					do
1134 					{
1135 						if(linePos > 0)
1136 						{
1137 							--linePos;
1138 							++bLinePos;
1139 
1140 							if(linePos < sPos)
1141 								sPos = linePos;
1142 						}
1143 					}while(linePos > 0 && std::isalnum(str[linePos]));
1144 				}
1145 				else if(c == 102) //alt f
1146 				{
1147 					do
1148 					{
1149 						if(bLinePos > 0)
1150 						{
1151 							++linePos;
1152 							--bLinePos;
1153 
1154 							if(sPos + usableLength == linePos)
1155 								++sPos;
1156 						}
1157 					}while(bLinePos > 0 && std::isalnum(str[linePos]));
1158 				}
1159 				else if(c == 127) //alt backspace
1160 				{
1161 					bool foundNonWhitespace = 0;
1162 					do
1163 					{
1164 						if(linePos > 0)
1165 						{
1166 							if(str[linePos-1] != ' ' && str[linePos-1] != '\t')
1167 								foundNonWhitespace = 1;
1168 
1169 							str = str.substr(0, linePos-1) + str.substr(linePos, str.size()-linePos);
1170 							--linePos;
1171 
1172 							if(sPos > 0 && str.size() - sPos < usableLength)
1173 								--sPos;
1174 						}
1175 						else
1176 							break;
1177 					}while(!foundNonWhitespace || (linePos > 0 && std::isalnum(str[linePos-1])));
1178 				}
1179 			}
1180 			else
1181 			{
1182 				str = str.substr(0, linePos) + c + str.substr(linePos, str.size()-linePos);
1183 				++linePos;
1184 
1185 				if(sPos + usableLength +1 == linePos)
1186 					++sPos;
1187 			}
1188 
1189 			//write_input_line(lang, pwd, promptCh, str, sPos, usableLength, linePos, bLinePos);
1190 		}
1191 
1192 		disable_raw_mode();
1193 
1194 		return 0;
1195 	}
1196 #endif
1197