diff options
-rw-r--r-- | boxes.c | 169 |
1 files changed, 61 insertions, 108 deletions
@@ -494,7 +494,7 @@ typedef struct _view view; | |||
494 | 494 | ||
495 | typedef void (*boxFunction) (box *box); | 495 | typedef void (*boxFunction) (box *box); |
496 | typedef void (*eventHandler) (view *view); | 496 | typedef void (*eventHandler) (view *view); |
497 | typedef char *(*CSIhandler) (long extra, int *code, int count); | 497 | typedef void (*CSIhandler) (long extra, int *code, int count); |
498 | 498 | ||
499 | struct function | 499 | struct function |
500 | { | 500 | { |
@@ -1786,37 +1786,7 @@ void nop(view *view) | |||
1786 | } | 1786 | } |
1787 | 1787 | ||
1788 | 1788 | ||
1789 | static void lineChar(long extra, char *buffer) | 1789 | static void termSize(long extra, int *params, int count) |
1790 | { | ||
1791 | struct _view *view = (struct _view *) extra; // Though we pretty much stomp on this straight away. | ||
1792 | |||
1793 | // Coz things might change out from under us, find the current view. | ||
1794 | if (commandMode) view = commandLine; | ||
1795 | else view = currentBox->view; | ||
1796 | |||
1797 | // TODO - Should check for tabs to, and insert them. | ||
1798 | // Though better off having a function for that? | ||
1799 | mooshStrings(view->line, buffer, view->iX, 0, !TT.overWriteMode); | ||
1800 | view->oW = formatLine(view, view->line->line, &(view->output)); | ||
1801 | moveCursorRelative(view, strlen(buffer), 0, 0, 0); | ||
1802 | updateLine(view); | ||
1803 | } | ||
1804 | |||
1805 | static struct keyCommand * lineCommand(long extra, char *sequence) | ||
1806 | { | ||
1807 | struct _view *view = (struct _view *) extra; // Though we pretty much stomp on this straight away. | ||
1808 | |||
1809 | // Coz things might change out from under us, find the current view. | ||
1810 | if (commandMode) view = commandLine; | ||
1811 | else view = currentBox->view; | ||
1812 | |||
1813 | doCommand(view, sequence); | ||
1814 | |||
1815 | // This is using the currentBox instead of view, coz the command line keys are part of the box context now, not separate. | ||
1816 | return currentBox->view->content->context->modes[currentBox->view->mode].keys; | ||
1817 | } | ||
1818 | |||
1819 | char *termSize(long extra, int *params, int count) | ||
1820 | { | 1790 | { |
1821 | struct _view *view = (struct _view *) extra; // Though we pretty much stomp on this straight away. | 1791 | struct _view *view = (struct _view *) extra; // Though we pretty much stomp on this straight away. |
1822 | int r = params[0], c = params[1]; | 1792 | int r = params[0], c = params[1]; |
@@ -1840,8 +1810,6 @@ char *termSize(long extra, int *params, int count) | |||
1840 | else view = currentBox->view; | 1810 | else view = currentBox->view; |
1841 | updateLine(view); | 1811 | updateLine(view); |
1842 | } | 1812 | } |
1843 | |||
1844 | return NULL; | ||
1845 | } | 1813 | } |
1846 | 1814 | ||
1847 | struct CSI | 1815 | struct CSI |
@@ -1856,21 +1824,54 @@ struct CSI CSI_terminators[] = | |||
1856 | {NULL, NULL} | 1824 | {NULL, NULL} |
1857 | }; | 1825 | }; |
1858 | 1826 | ||
1827 | static int handleKeySequence(long extra, char *sequence) | ||
1828 | { | ||
1829 | struct _view *view = (struct _view *) extra; // Though we pretty much stomp on this straight away. | ||
1830 | struct keyCommand *commands = currentBox->view->content->context->modes[currentBox->view->mode].keys; | ||
1831 | int j; | ||
1832 | |||
1833 | // Coz things might change out from under us, find the current view. | ||
1834 | if (commandMode) view = commandLine; | ||
1835 | else view = currentBox->view; | ||
1836 | |||
1837 | // Search for a key sequence bound to a command. | ||
1838 | for (j = 0; commands[j].key; j++) | ||
1839 | { | ||
1840 | if (strcmp(commands[j].key, sequence) == 0) | ||
1841 | { | ||
1842 | doCommand(view, commands[j].command); | ||
1843 | return 1; | ||
1844 | } | ||
1845 | } | ||
1846 | |||
1847 | if ((0 == sequence[1]) && isprint(sequence[0])) // See if it's an ordinary key. | ||
1848 | { | ||
1849 | // TODO - Should check for tabs to, and insert them. | ||
1850 | // Though better off having a function for that? | ||
1851 | mooshStrings(view->line, sequence, view->iX, 0, !TT.overWriteMode); | ||
1852 | view->oW = formatLine(view, view->line->line, &(view->output)); | ||
1853 | moveCursorRelative(view, strlen(sequence), 0, 0, 0); | ||
1854 | updateLine(view); | ||
1855 | return 1; | ||
1856 | } | ||
1857 | |||
1858 | return 0; | ||
1859 | } | ||
1860 | |||
1859 | // Basically this is the main loop. | 1861 | // Basically this is the main loop. |
1860 | 1862 | ||
1861 | // TODO - Unhandled complications - | 1863 | // TODO - Unhandled complications - |
1862 | // Less and more have the "ZZ" command, but nothing else seems to have multi ordinary character commands. | 1864 | // Less and more have the "ZZ" command, but nothing else seems to have multi ordinary character commands. |
1863 | 1865 | ||
1864 | void handle_keys(long extra, void (*lineChar)(long extra, char *buffer), struct keyCommand * (*lineCommand)(long extra, char *sequence)) | 1866 | void handle_keys(long extra, int (*handle_sequence)(long extra, char *sequence)) |
1865 | { | 1867 | { |
1866 | fd_set selectFds; | 1868 | fd_set selectFds; |
1867 | struct timespec timeout; | 1869 | struct timespec timeout; |
1868 | sigset_t signalMask; | 1870 | sigset_t signalMask; |
1869 | 1871 | ||
1870 | // Get the initial command set. | 1872 | // Get the initial command set. |
1871 | struct keyCommand *commands = lineCommand(extra, ""); | ||
1872 | char buffer[20], sequence[20], csFinal[8]; | 1873 | char buffer[20], sequence[20], csFinal[8]; |
1873 | int csi = 0, csCount = 0, csIndex = 0, csParams[8], buffIndex = 0; | 1874 | int buffIndex = 0; |
1874 | // TODO - multiline editLine is an advanced feature. Editing boxes just moves the editLine up and down. | 1875 | // TODO - multiline editLine is an advanced feature. Editing boxes just moves the editLine up and down. |
1875 | // uint16_t h = 1; | 1876 | // uint16_t h = 1; |
1876 | // TODO - should check if it's at the top of the box, then grow it down instead of up if so. | 1877 | // TODO - should check if it's at the top of the box, then grow it down instead of up if so. |
@@ -1885,16 +1886,7 @@ void handle_keys(long extra, void (*lineChar)(long extra, char *buffer), struct | |||
1885 | TT.stillRunning = 1; | 1886 | TT.stillRunning = 1; |
1886 | while (TT.stillRunning) | 1887 | while (TT.stillRunning) |
1887 | { | 1888 | { |
1888 | int j, p; | 1889 | int j, p, csi = 0; |
1889 | char *command = NULL; | ||
1890 | |||
1891 | if (0 == buffIndex) | ||
1892 | { | ||
1893 | buffer[0] = 0; | ||
1894 | csi = 0; | ||
1895 | csCount = 0; | ||
1896 | csIndex = 0; | ||
1897 | } | ||
1898 | 1890 | ||
1899 | // Apparently it's more portable to reset these each time. | 1891 | // Apparently it's more portable to reset these each time. |
1900 | FD_ZERO(&selectFds); | 1892 | FD_ZERO(&selectFds); |
@@ -1913,7 +1905,7 @@ void handle_keys(long extra, void (*lineChar)(long extra, char *buffer), struct | |||
1913 | sigWinch = 0; | 1905 | sigWinch = 0; |
1914 | } | 1906 | } |
1915 | 1907 | ||
1916 | // TODO - Should only ask for a time out after we get an Escape. | 1908 | // TODO - Should only ask for a time out after we get an Escape, or the user requested time ticks. |
1917 | // I wanted to use poll, but that would mean using ppoll, which is Linux only, and involves defining swear words to get it. | 1909 | // I wanted to use poll, but that would mean using ppoll, which is Linux only, and involves defining swear words to get it. |
1918 | p = pselect(0 + 1, &selectFds, NULL, NULL, &timeout, &signalMask); | 1910 | p = pselect(0 + 1, &selectFds, NULL, NULL, &timeout, &signalMask); |
1919 | if (0 > p) | 1911 | if (0 > p) |
@@ -1922,18 +1914,18 @@ void handle_keys(long extra, void (*lineChar)(long extra, char *buffer), struct | |||
1922 | continue; | 1914 | continue; |
1923 | perror_exit("poll"); | 1915 | perror_exit("poll"); |
1924 | } | 1916 | } |
1925 | if (0 == p) // A timeout, trigger a time event. | 1917 | else if (0 == p) // A timeout, trigger a time event. |
1926 | { | 1918 | { |
1927 | if ((1 == buffIndex) && ('\x1B' == buffer[0])) | 1919 | if ((0 == buffer[1]) && ('\x1B' == buffer[0])) |
1928 | { | 1920 | { |
1929 | // After a short delay to check, this is a real Escape key, not part of an escape sequence, so deal with it. | 1921 | // After a short delay to check, this is a real Escape key, not part of an escape sequence, so deal with it. |
1922 | // TODO - so far the only uses of this have the escape at the start, but maybe a strcat is needed instead later? | ||
1930 | strcpy(sequence, "^["); | 1923 | strcpy(sequence, "^["); |
1931 | buffIndex = 0; | 1924 | buffer[0] = buffIndex = 0; |
1932 | } | 1925 | } |
1933 | // TODO - Send a timer event to lineCommand(). This wont be a precise timed event, but don't think we need one. | 1926 | // TODO - Call some sort of timer tick callback. This wont be a precise timed event, but don't think we need one. |
1934 | } | 1927 | } |
1935 | 1928 | else if ((0 < p) && FD_ISSET(0, &selectFds)) | |
1936 | if (FD_ISSET(0, &selectFds)) | ||
1937 | { | 1929 | { |
1938 | // I am assuming that we get the input atomically, each multibyte key fits neatly into one read. | 1930 | // I am assuming that we get the input atomically, each multibyte key fits neatly into one read. |
1939 | // If that's not true (which is entirely likely), then we have to get complicated with circular buffers and stuff, or just one byte at a time. | 1931 | // If that's not true (which is entirely likely), then we have to get complicated with circular buffers and stuff, or just one byte at a time. |
@@ -1963,7 +1955,7 @@ void handle_keys(long extra, void (*lineChar)(long extra, char *buffer), struct | |||
1963 | fflush(stderr); | 1955 | fflush(stderr); |
1964 | buffIndex = 0; | 1956 | buffIndex = 0; |
1965 | } | 1957 | } |
1966 | else buffer[buffIndex] = 0; | 1958 | buffer[buffIndex] = 0; |
1967 | } | 1959 | } |
1968 | } | 1960 | } |
1969 | 1961 | ||
@@ -1991,7 +1983,7 @@ void handle_keys(long extra, void (*lineChar)(long extra, char *buffer), struct | |||
1991 | if (strcmp(keys[j].code, buffer) == 0) | 1983 | if (strcmp(keys[j].code, buffer) == 0) |
1992 | { | 1984 | { |
1993 | strcat(sequence, keys[j].name); | 1985 | strcat(sequence, keys[j].name); |
1994 | buffIndex = 0; | 1986 | buffer[0] = buffIndex = 0; |
1995 | csi = 0; | 1987 | csi = 0; |
1996 | break; | 1988 | break; |
1997 | } | 1989 | } |
@@ -2015,9 +2007,10 @@ TODO So abort the current CSI and start from scratch. | |||
2015 | */ | 2007 | */ |
2016 | 2008 | ||
2017 | char *t; | 2009 | char *t; |
2010 | int csIndex = 1, csParams[8]; | ||
2018 | 2011 | ||
2019 | csIndex = 1; | ||
2020 | csFinal[0] = 0; | 2012 | csFinal[0] = 0; |
2013 | p = 0; | ||
2021 | // Unspecified params default to a value that is command dependant. | 2014 | // Unspecified params default to a value that is command dependant. |
2022 | // However, they will never be negative, so we can use -1 to flag a default value. | 2015 | // However, they will never be negative, so we can use -1 to flag a default value. |
2023 | for (j = 0; j < (sizeof(csParams) / sizeof(*csParams)); j++) | 2016 | for (j = 0; j < (sizeof(csParams) / sizeof(*csParams)); j++) |
@@ -2053,9 +2046,9 @@ TODO So abort the current CSI and start from scratch. | |||
2053 | if (';' != buffer[csIndex] || (!t)) | 2046 | if (';' != buffer[csIndex] || (!t)) |
2054 | { | 2047 | { |
2055 | // TODO - Might be ":" in the number somewhere, but we are not expecting any in anything we do. | 2048 | // TODO - Might be ":" in the number somewhere, but we are not expecting any in anything we do. |
2056 | csParams[csCount] = atoi(&buffer[csIndex]); | 2049 | csParams[p] = atoi(&buffer[csIndex]); |
2057 | } | 2050 | } |
2058 | csCount++; | 2051 | p++; |
2059 | csIndex = j + 1; | 2052 | csIndex = j + 1; |
2060 | } | 2053 | } |
2061 | j++; | 2054 | j++; |
@@ -2068,9 +2061,7 @@ TODO So abort the current CSI and start from scratch. | |||
2068 | { | 2061 | { |
2069 | if (strcmp(CSI_terminators[j].code, csFinal) == 0) | 2062 | if (strcmp(CSI_terminators[j].code, csFinal) == 0) |
2070 | { | 2063 | { |
2071 | t = CSI_terminators[j].func(extra, csParams, csCount); | 2064 | CSI_terminators[j].func(extra, csParams, p); |
2072 | if (t) | ||
2073 | strcpy(sequence, t); | ||
2074 | break; | 2065 | break; |
2075 | } | 2066 | } |
2076 | } | 2067 | } |
@@ -2078,57 +2069,19 @@ TODO So abort the current CSI and start from scratch. | |||
2078 | 2069 | ||
2079 | csi = 0; | 2070 | csi = 0; |
2080 | // Wether or not it's a CSI we understand, it's been handled either here or in the key sequence scanning above. | 2071 | // Wether or not it's a CSI we understand, it's been handled either here or in the key sequence scanning above. |
2081 | buffIndex = 0; | 2072 | buffer[0] = buffIndex = 0; |
2082 | } | ||
2083 | |||
2084 | // See if it's an ordinary key, | ||
2085 | if ((1 == buffIndex) && isprint(buffer[0])) | ||
2086 | { | ||
2087 | // Here we want to run it through the command finder first, and only "insert" it if it's not a command. | ||
2088 | // Yes, this is duplicated below. | ||
2089 | for (j = 0; commands[j].key; j++) | ||
2090 | { | ||
2091 | if (strcmp(commands[j].key, buffer) == 0) | ||
2092 | { | ||
2093 | strcpy(sequence, buffer); | ||
2094 | command = sequence; | ||
2095 | break; | ||
2096 | } | ||
2097 | } | ||
2098 | if (NULL == command) | ||
2099 | { | ||
2100 | // If there's an outstanding sequence, add this to the end of it. | ||
2101 | if (sequence[0]) strcat(sequence, buffer); | ||
2102 | else lineChar(extra, buffer); | ||
2103 | } | ||
2104 | buffIndex = 0; | ||
2105 | } | 2073 | } |
2106 | 2074 | ||
2107 | // Search for a key sequence bound to a command. | 2075 | // Pass the result to the callback. |
2108 | if (sequence[0]) | 2076 | if (sequence[0] || buffer[0]) |
2109 | { | 2077 | { |
2110 | if (sizeof(sequence) < (strlen(sequence) + 1)) | 2078 | char b[strlen(sequence) + strlen(buffer) + 1]; |
2111 | { | ||
2112 | fprintf(stderr, "Full key sequence buffer - %s \n", sequence); | ||
2113 | fflush(stderr); | ||
2114 | sequence[0] = 0; | ||
2115 | } | ||
2116 | 2079 | ||
2117 | if (NULL == command) | 2080 | sprintf(b, "%s%s", sequence, buffer); |
2118 | { | 2081 | if (handle_sequence(extra, b)) |
2119 | for (j = 0; commands[j].key; j++) | ||
2120 | { | ||
2121 | if (strcmp(commands[j].key, sequence) == 0) | ||
2122 | { | ||
2123 | command = commands[j].command; | ||
2124 | break; | ||
2125 | } | ||
2126 | } | ||
2127 | } | ||
2128 | if (command) | ||
2129 | { | 2082 | { |
2130 | commands = lineCommand(extra, command); | ||
2131 | sequence[0] = 0; | 2083 | sequence[0] = 0; |
2084 | buffer[0] = buffIndex = 0; | ||
2132 | } | 2085 | } |
2133 | } | 2086 | } |
2134 | } | 2087 | } |
@@ -2908,7 +2861,7 @@ void boxes_main(void) | |||
2908 | updateLine(currentBox->view); | 2861 | updateLine(currentBox->view); |
2909 | 2862 | ||
2910 | // Run the main loop. | 2863 | // Run the main loop. |
2911 | handle_keys((long) currentBox->view, lineChar, lineCommand); | 2864 | handle_keys((long) currentBox->view, handleKeySequence); |
2912 | 2865 | ||
2913 | // TODO - Should remember to turn off mouse reporting when we leave. | 2866 | // TODO - Should remember to turn off mouse reporting when we leave. |
2914 | 2867 | ||