Browse Source

Completed history in-shell switching

Ivan Arkhipov 5 years ago
parent
commit
7b8f8d0cb4
4 changed files with 107 additions and 8 deletions
  1. 2 0
      CMakeLists.txt
  2. 31 4
      esh_history.c
  3. 2 2
      esh_history.h
  4. 72 2
      esh_main_loop.c

+ 2 - 0
CMakeLists.txt

@@ -11,6 +11,8 @@ add_compile_definitions(BUILD_REF="${BuildRef}")
 add_executable(shell
         esh_deinit.c
         esh_deinit.h
+        esh_history.c
+        esh_history.h
         esh_init.c
         esh_init.h
         esh_main_loop.c

+ 31 - 4
esh_history.c

@@ -1,9 +1,36 @@
 #include "esh_history.h"
 
-void addCommandToHistory(char* command) {
-	// TODO
+void EShAddCommandToHistory(char* command) {
+	int list_size = esh_info_global->history_command_list_size;
+	char** list = esh_info_global->history_command_list;
+
+	if (list_size == esh_info_global->history_limit) {
+		for (int i = 0; i <= list_size / 2; ++i) {
+			free(list[i]);
+		}
+
+		for (int i = list_size / 2 + 1; i < list_size; ++i) {
+			list[i - (list_size / 2 + 1)] = list[i];
+			list[i] = NULL;
+		}
+
+		esh_info_global->history_command_list_size -= list_size / 2 + 1;
+		list_size -= list_size / 2 + 1;
+	}
+
+	list[list_size] = malloc((strlen(command) + 1) * sizeof(char));
+	strcpy(list[list_size], command);
+	++esh_info_global->history_command_list_size;
 }
 
-char* receiveCommandFromHistory(int step = 1) {
-	// TODO
+char* EShReceiveCommandFromHistory(int step) {
+	int list_size = esh_info_global->history_command_list_size;
+	char** list = esh_info_global->history_command_list;
+	if (step >= list_size) {
+		return NULL;
+	}
+
+	char* fragment = malloc((strlen(list[list_size - step - 1]) + 1) * sizeof(char));
+	strcpy(fragment, list[list_size - step - 1]);
+	return fragment;
 }

+ 2 - 2
esh_history.h

@@ -3,9 +3,9 @@
 #ifndef ESH_HISTORY_H
 #define ESH_HISTORY_H
 
-void addCommandToHistory(char* command); // saves command copy to history list.
+void EShAddCommandToHistory(char* command); // saves command copy to history list.
 
-char* receiveCommandFromHistory(int step = 1); // returns copy of command, executed _step_ steps ago.
+char* EShReceiveCommandFromHistory(int step); // returns copy of command, executed _step_ steps ago.
 
 
 #endif // ESH_HISTORY_H

+ 72 - 2
esh_main_loop.c

@@ -1,5 +1,6 @@
 #include "esh_main_loop.h"
 #include "esh_misc.h"
+#include "esh_history.h"
 
 void EShRunLoop() {
     struct termios orig_term_attr;
@@ -13,15 +14,21 @@ void EShRunLoop() {
     new_term_attr.c_cc[VMIN] = 1;
     tcsetattr(fileno(stdin), TCSANOW, &new_term_attr);
 
+	char* command = malloc(esh_info_global->max_command_length);
+	char* uncomplete_command = malloc(esh_info_global->max_command_length); // Used to restore after moves history
+
 	for (;;) {
 		EShShowMsg();
-		char* command = malloc(esh_info_global->max_command_length);
 		memset(command, 0, esh_info_global->max_command_length);
+
 		int command_length = 0;
 		int current_command_pos = 0;
+    	int current_history_step = 0;
 
 		char input_char;
 
+		memset(uncomplete_command, 0, esh_info_global->max_command_length);
+
 		while (input_char = fgetc(stdin)) {
 			if (input_char == 10) {
 				printf("\n");
@@ -35,10 +42,72 @@ void EShRunLoop() {
 			if (input_char == '\033') { // Arrow up/down/left/right sequence
 				fgetc(stdin);
 			    switch(fgetc(stdin)) {
-			        case 'A': // Up
+			        case 'A':
+			        { 
+			        	if (current_history_step == 0) {
+			        		strcpy(uncomplete_command, command);
+			        	}
+
+			        	char* new_command = EShReceiveCommandFromHistory(current_history_step);
+			        	if (new_command != NULL) {
+			        		++current_history_step;
+			        		for (int i = current_command_pos; i < command_length; ++i) {
+			        			printf(" ");
+			        			++current_command_pos;
+			        		}
+
+			        		for (int i = current_command_pos; i > 0; --i) {
+			        			printf("\b \b");
+			        		}
+
+	        				strcpy(command, new_command);
+			        		command_length = strlen(new_command);
+			        		current_command_pos = command_length;
+
+		        			for (int i = 0; i < command_length; ++i) {
+		        				printf("%c", command[i]);
+			        		}
+			        	}
+
+			        	free(new_command);
 			        	break;
+			        }
 			        case 'B': // Down
+			        {
+			        	char* new_command;
+
+		        		if (current_history_step > 0) {
+		        			--current_history_step;
+		        		}
+
+	        			if (current_history_step > 0) {
+		        			new_command = EShReceiveCommandFromHistory(current_history_step - 1);
+		        		} else {
+		        			new_command = uncomplete_command;
+		        		}
+
+		        		for (int i = current_command_pos; i < command_length; ++i) {
+		        			printf(" ");
+		        			++current_command_pos;
+		        		}
+
+		        		for (int i = current_command_pos; i > 0; --i) {
+		        			printf("\b \b");
+		        		}
+
+        				strcpy(command, new_command);
+		        		command_length = strlen(new_command);
+		        		current_command_pos = command_length;
+
+	        			for (int i = 0; i < command_length; ++i) {
+	        				printf("%c", command[i]);
+		        		}
+
+		        		if (current_history_step > 0) {
+		        			free(new_command); 
+		        		}
 			        	break;
+			        }
 			        case 'C': // Right
 			        	if (current_command_pos < command_length) {
 			        		printf("%c", command[current_command_pos]);
@@ -110,6 +179,7 @@ void EShRunLoop() {
 			continue;
 		}
 
+		EShAddCommandToHistory(command);
 		int pid = fork();
 		if (pid == 0) {
 			execlp(command, command, NULL);