diff --git a/yat/.gitignore b/yat/.gitignore new file mode 100644 index 0000000..1a1ea2b --- /dev/null +++ b/yat/.gitignore @@ -0,0 +1,10 @@ +Makefile +.moc +.obj +yat +yat.pro.user +yat.pro.user.1.3 +yat.pro.user.2.6pre1 +yat_declarative/qrc_qml_sources.cpp + + diff --git a/yat/README b/yat/README new file mode 100644 index 0000000..8f8c732 --- /dev/null +++ b/yat/README @@ -0,0 +1,6 @@ +YAT is a terminal emulator written in qml and c++ + +The main goal of the project was to find out if it was possible to use qml to +write a terminal emulator which performed on par with xterm and konsole. + +Turns out, it's possible. diff --git a/yat/backend/backend.pri b/yat/backend/backend.pri new file mode 100644 index 0000000..240fd91 --- /dev/null +++ b/yat/backend/backend.pri @@ -0,0 +1,31 @@ +DEPENDPATH += $$PWD +INCLUDEPATH += $$PWD + +LIBS += -lutil -L/home/jlind/install/lib + +MOC_DIR = .moc +OBJECTS_DIR = .obj + +HEADERS += \ + $$PWD/yat_pty.h \ + $$PWD/text.h \ + $$PWD/controll_chars.h \ + $$PWD/parser.h \ + $$PWD/screen.h \ + $$PWD/line.h \ + $$PWD/color_palette.h \ + $$PWD/text_style.h \ + $$PWD/update_action.h \ + $$PWD/screen_data.h + +SOURCES += \ + $$PWD/yat_pty.cpp \ + $$PWD/text.cpp \ + $$PWD/controll_chars.cpp \ + $$PWD/parser.cpp \ + $$PWD/screen.cpp \ + $$PWD/line.cpp \ + $$PWD/color_palette.cpp \ + $$PWD/text_style.cpp \ + $$PWD/update_action.cpp \ + $$PWD/screen_data.cpp diff --git a/yat/backend/color_palette.cpp b/yat/backend/color_palette.cpp new file mode 100644 index 0000000..64aaa1f --- /dev/null +++ b/yat/backend/color_palette.cpp @@ -0,0 +1,49 @@ +#include "color_palette.h" + +ColorPalette::ColorPalette() + : m_normalColors(numberOfColors) + , m_lightColors(numberOfColors) + , m_intenseColors(numberOfColors) +{ + m_normalColors[0].setRgb(0,0,0); + m_normalColors[1].setRgb(194,54,33); + m_normalColors[2].setRgb(37,188,36); + m_normalColors[3].setRgb(173,173,39); + m_normalColors[4].setRgb(63,84,255); + m_normalColors[5].setRgb(211,56,211); + m_normalColors[6].setRgb(51,187,199); + m_normalColors[7].setRgb(229,229,229); + m_normalColors[8].setRgb(178,178,178); + m_normalColors[9].setAlpha(0); + + m_lightColors[0].setRgb(129,131,131); + m_lightColors[1].setRgb(252,57,31); + m_lightColors[2].setRgb(49,231,34); + m_lightColors[3].setRgb(234,236,35); + m_lightColors[4].setRgb(88,51,255); + m_lightColors[5].setRgb(249,53,248); + m_lightColors[6].setRgb(20,240,240); + m_lightColors[7].setRgb(233,233,233); + m_lightColors[8].setRgb(220,220,220); + m_lightColors[9].setRgb(50,50,50); + +} + +QColor ColorPalette::color(ColorPalette::Color color, bool bold) const +{ + if (bold) + return m_lightColors.at(color); + + return m_normalColors.at(color); +} + +QColor ColorPalette::normalColor(ColorPalette::Color color) const +{ + return m_normalColors.at(color); +} + +QColor ColorPalette::lightColor(ColorPalette::Color color) const +{ + return m_lightColors.at(color); +} + diff --git a/yat/backend/color_palette.h b/yat/backend/color_palette.h new file mode 100644 index 0000000..e9f6a7c --- /dev/null +++ b/yat/backend/color_palette.h @@ -0,0 +1,38 @@ +#ifndef COLOR_PALETTE_H +#define COLOR_PALETTE_H + +#include + +#include + +class ColorPalette +{ +public: + ColorPalette(); + + + enum Color { + Black, + Red, + Green, + Yellow, + Blue, + Magenta, + Cyan, + White, + DefaultForground, + DefaultBackground, + numberOfColors + }; + + QColor color(Color color, bool bold) const; + QColor normalColor(Color color) const; + QColor lightColor(Color color) const; + +private: + QVector m_normalColors; + QVector m_lightColors; + QVector m_intenseColors; +}; + +#endif // COLOR_PALETTE_H diff --git a/yat/backend/controll_chars.cpp b/yat/backend/controll_chars.cpp new file mode 100644 index 0000000..084b17e --- /dev/null +++ b/yat/backend/controll_chars.cpp @@ -0,0 +1,776 @@ +/******************************************************************************* +* Copyright (c) 2013 Jørgen Lind +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +*******************************************************************************/ +#include "controll_chars.h" + +namespace C0 { +QDebug operator<<(QDebug debug, C0 character) { + bool insert_space = debug.autoInsertSpaces(); + debug.setAutoInsertSpaces(false); + debug << "C0::"; + switch (character) { + case NUL: + debug << "NUL"; + break; + case SOH: + debug << "SOH"; + break; + case STX: + debug << "STX"; + break; + case ETX: + debug << "ETX"; + break; + case EOT: + debug << "EOT"; + break; + case ENQ: + debug << "ENQ"; + break; + case ACK: + debug << "ACK"; + break; + case BEL: + debug << "BEL"; + break; + case BS: + debug << "BS"; + break; + case HT: + debug << "HT"; + break; + case LF: + debug << "LF"; + break; + case VT: + debug << "VT"; + break; + case FF: + debug << "FF"; + break; + case CR: + debug << "CR"; + break; + case SOorLS1: + debug << "SOorLS1"; + break; + case SIorLS0: + debug << "SIorLS0"; + break; + case DLE: + debug << "DLE"; + break; + case DC1: + debug << "DC1"; + break; + case DC2: + debug << "DC2"; + break; + case DC3: + debug << "DC3"; + break; + case DC4: + debug << "DC4"; + break; + case NAK: + debug << "NAK"; + break; + case SYN: + debug << "SYN"; + break; + case ETB: + debug << "ETB"; + break; + case CAN: + debug << "CAN"; + break; + case EM: + debug << "EM"; + break; + case SUB: + debug << "SUB"; + break; + case ESC: + debug << "ESC"; + break; + case IS4: + debug << "IS4"; + break; + case IS3: + debug << "IS3"; + break; + case IS2: + debug << "IS2"; + break; + case IS1: + debug << "IS1"; + break; + case C0_END: + debug << "C0_END"; + break; + default: + debug << qPrintable(QString("0x%1").arg(character,0,16)); + break; + } + debug.setAutoInsertSpaces(insert_space); + return debug; +} +} + +namespace C1_7bit { +QDebug operator<<(QDebug debug, C1_7bit character) { + bool insert_space = debug.autoInsertSpaces(); + debug.setAutoInsertSpaces(false); + debug << "C1_7bit::"; + switch(character) { + case NOT_DEFINED: + debug << "NOT_DEFINED"; + break; + case NOT_DEFINED1: + debug << "NOT_DEFINED1"; + break; + case BPH: + debug << "BPH"; + break; + case NBH: + debug << "NBH"; + break; + case NOT_DEFINED2: + debug << "NOT_DEFINED2"; + break; + case NEL: + debug << "NEL"; + break; + case SSA: + debug << "SSA"; + break; + case ESA: + debug << "ESA"; + break; + case HTS: + debug << "HTS"; + break; + case HTJ: + debug << "HTJ"; + break; + case VTS: + debug << "VTS"; + break; + case PLD: + debug << "PLD"; + break; + case PLU: + debug << "PLU"; + break; + case RI : + debug << "RI "; + break; + case SS2: + debug << "SS2"; + break; + case SS3: + debug << "SS3"; + break; + case DCS: + debug << "DCS"; + break; + case PU1: + debug << "PU1"; + break; + case PU2: + debug << "PU2"; + break; + case STS: + debug << "STS"; + break; + case CCH: + debug << "CCH"; + break; + case MW : + debug << "MW "; + break; + case SPA: + debug << "SPA"; + break; + case EPA: + debug << "EPA"; + break; + case SOS: + debug << "SOS"; + break; + case NOT_DEFINED3: + debug << "NOT_DEFINED3"; + break; + case SCI: + debug << "SCI"; + break; + case CSI: + debug << "CSI"; + break; + case ST : + debug << "ST "; + break; + case OSC: + debug << "OSC"; + break; + case PM : + debug << "PM "; + break; + case APC: + debug << "APC"; + break; + case C1_7bit_Stop: + debug << "C1_7bit_Stop"; + break; + default: + debug << qPrintable(QString("0x%1").arg(character,0,16)); + break; + } + debug.setAutoInsertSpaces(insert_space); + return debug; +} +} + +namespace C1_8bit { +QDebug operator<<(QDebug debug, C1_8bit character) { + bool insert_space = debug.autoInsertSpaces(); + debug.setAutoInsertSpaces(false); + debug << "C1_8bit::"; + switch(character) { + case NOT_DEFINED: + debug << "NOT_DEFINED"; + break; + case NOT_DEFINED1: + debug << "NOT_DEFINED1"; + break; + case BPH: + debug << "BPH"; + break; + case NBH: + debug << "NBH"; + break; + case NOT_DEFINED2: + debug << "NOT_DEFINED2"; + break; + case NEL: + debug << "NEL"; + break; + case SSA: + debug << "SSA"; + break; + case ESA: + debug << "ESA"; + break; + case HTS: + debug << "HTS"; + break; + case HTJ: + debug << "HTJ"; + break; + case VTS: + debug << "VTS"; + break; + case PLD: + debug << "PLD"; + break; + case PLU: + debug << "PLU"; + break; + case RI : + debug << "RI "; + break; + case SS2: + debug << "SS2"; + break; + case SS3: + debug << "SS3"; + break; + case DCS: + debug << "DCS"; + break; + case PU1: + debug << "PU1"; + break; + case PU2C1_7bit: + debug << "PU2C1_7bit"; + break; + case STS: + debug << "STS"; + break; + case CCH: + debug << "CCH"; + break; + case MW : + debug << "MW "; + break; + case SPA: + debug << "SPA"; + break; + case EPA: + debug << "EPA"; + break; + case SOS: + debug << "SOS"; + break; + case NOT_DEFINED3: + debug << "NOT_DEFINED3"; + break; + case SCI: + debug << "SCI"; + break; + case CSI: + debug << "CSI"; + break; + case ST : + debug << "ST "; + break; + case OSC: + debug << "OSC"; + break; + case PM : + debug << "PM "; + break; + case APC: + debug << "APC"; + break; + case C1_8bit_Stop: + debug << "C1_8bit_Stop"; + break; + default: + debug << qPrintable(QString("0x%1").arg(character,0,16)); + break; + } + debug.setAutoInsertSpaces(insert_space); + return debug; +} +} +namespace FinalBytesNoIntermediate { +QDebug operator<<(QDebug debug, FinalBytesNoIntermediate character) { + bool insert_space = debug.autoInsertSpaces(); + debug.setAutoInsertSpaces(false); + debug << "FinalBytesNoIntermediate::"; + switch(character) { + case ICH: + debug << "ICH"; + break; + case CUU: + debug << "CUU"; + break; + case CUD: + debug << "CUD"; + break; + case CUF: + debug << "CUF"; + break; + case CUB: + debug << "CUB"; + break; + case CNL: + debug << "CNL"; + break; + case CPL: + debug << "CPL"; + break; + case CHA: + debug << "CHA"; + break; + case CUP: + debug << "CUP"; + break; + case CHT: + debug << "CHT"; + break; + case ED: + debug << "ED"; + break; + case EL: + debug << "EL"; + break; + case IL: + debug << "IL"; + break; + case DL: + debug << "DL"; + break; + case EF: + debug << "EF"; + break; + case EA: + debug << "EA"; + break; + case DCH: + debug << "DCH"; + break; + case SSE: + debug << "SSE"; + break; + case CPR: + debug << "CPR"; + break; + case SU: + debug << "SU"; + break; + case SD: + debug << "SD"; + break; + case NP: + debug << "NP"; + break; + case PP: + debug << "PP"; + break; + case CTC: + debug << "CTC"; + break; + case ECH: + debug << "ECH"; + break; + case CVT: + debug << "CVT"; + break; + case CBT: + debug << "CBT"; + break; + case SRS: + debug << "SRS"; + break; + case PTX: + debug << "PTX"; + break; + case SDS: + debug << "SDS"; + break; + case SIMD: + debug << "SIMD"; + break; + case NOT_DEFINED: + debug << "NOT_DEFINED"; + break; + case HPA: + debug << "HPA"; + break; + case HPR: + debug << "HPR"; + break; + case REP: + debug << "REP"; + break; + case DA: + debug << "DA"; + break; + case VPA: + debug << "VPA"; + break; + case VPR: + debug << "VPR"; + break; + case HVP: + debug << "HVP"; + break; + case TBC: + debug << "TBC"; + break; + case SM: + debug << "SM"; + break; + case MC: + debug << "MC"; + break; + case HPB: + debug << "HPB"; + break; + case VPB: + debug << "VPB"; + break; + case RM: + debug << "RM"; + break; + case SGR: + debug << "SGR"; + break; + case DSR: + debug << "DSR"; + break; + case DAQ: + debug << "DAQ"; + break; + case Reserved0: + debug << "Reserved0"; + break; + case Reserved1: + debug << "Reserved1"; + break; + case Reserved2: + debug << "Reserved2"; + break; + case Reserved3: + debug << "Reserved3"; + break; + case Reserved4: + debug << "Reserved4"; + break; + case Reserved5: + debug << "Reserved5"; + break; + case Reserved6: + debug << "Reserved6"; + break; + case Reserved7: + debug << "Reserved7"; + break; + case Reserved8: + debug << "Reserved8"; + break; + case Reserved9: + debug << "Reserved9"; + break; + case Reserveda: + debug << "Reserveda"; + break; + case Reservedb: + debug << "Reservedb"; + break; + case Reservedc: + debug << "Reservedc"; + break; + case Reservedd: + debug << "Reservedd"; + break; + case Reservede: + debug << "Reservede"; + break; + case Reservedf: + debug << "Reservedf"; + break; + default: + debug << qPrintable(QString("0x%1").arg(character,0,16)); + break; + } + debug.setAutoInsertSpaces(insert_space); + return debug; +} +} + +namespace FinalBytesSingleIntermediate { +QDebug operator<<(QDebug debug, FinalBytesSingleIntermediate character) +{ + bool insert_space = debug.autoInsertSpaces(); + debug.setAutoInsertSpaces(false); + debug << "FinalBytesSingleIntermediate::"; + switch(character) { + case SL: + debug << "SL"; + break; + case SR: + debug << "SR"; + break; + case GSM: + debug << "GSM"; + break; + case GSS: + debug << "GSS"; + break; + case FNT: + debug << "FNT"; + break; + case TSS: + debug << "TSS"; + break; + case JFY: + debug << "JFY"; + break; + case SPI: + debug << "SPI"; + break; + case QUAD: + debug << "QUAD"; + break; + case SSU: + debug << "SSU"; + break; + case PFS: + debug << "PFS"; + break; + case SHS: + debug << "SHS"; + break; + case SVS: + debug << "SVS"; + break; + case IGS: + debug << "IGS"; + break; + case NOT_DEFINED: + debug << "NOT_DEFINED"; + break; + case IDCS: + debug << "IDCS"; + break; + case PPA: + debug << "PPA"; + break; + case PPR: + debug << "PPR"; + break; + case PPB: + debug << "PPB"; + break; + case SPD: + debug << "SPD"; + break; + case DTA: + debug << "DTA"; + break; + case SHL: + debug << "SHL"; + break; + case SLL: + debug << "SLL"; + break; + case FNK: + debug << "FNK"; + break; + case SPQR: + debug << "SPQR"; + break; + case SEF: + debug << "SEF"; + break; + case PEC: + debug << "PEC"; + break; + case SSW: + debug << "SSW"; + break; + case SACS: + debug << "SACS"; + break; + case SAPV: + debug << "SAPV"; + break; + case STAB: + debug << "STAB"; + break; + case GCC: + debug << "GCC"; + break; + case TATE: + debug << "TATE"; + break; + case TALE: + debug << "TALE"; + break; + case TAC: + debug << "TAC"; + break; + case TCC: + debug << "TCC"; + break; + case TSR: + debug << "TSR"; + break; + case SCO: + debug << "SCO"; + break; + case SRCS: + debug << "SRCS"; + break; + case SCS: + debug << "SCS"; + break; + case SLS: + debug << "SLS"; + break; + case NOT_DEFINED2: + debug << "NOT_DEFINED2"; + break; + case NOT_DEFINED3: + debug << "NOT_DEFINED3"; + break; + case SCP: + debug << "SCP"; + break; + case NOT_DEFINED4: + debug << "NOT_DEFINED4"; + break; + case NOT_DEFINED5: + debug << "NOT_DEFINED5"; + break; + case NOT_DEFINED6: + debug << "NOT_DEFINED6"; + break; + case NOT_DEFINED7: + debug << "NOT_DEFINED7"; + break; + case Reserved0: + debug << "Reserved0"; + break; + case Reserved1: + debug << "Reserved1"; + break; + case Reserved2: + debug << "Reserved2"; + break; + case Reserved3: + debug << "Reserved3"; + break; + case Reserved4: + debug << "Reserved4"; + break; + case Reserved5: + debug << "Reserved5"; + break; + case Reserved6: + debug << "Reserved6"; + break; + case Reserved7: + debug << "Reserved7"; + break; + case Reserved8: + debug << "Reserved8"; + break; + case Reserved9: + debug << "Reserved9"; + break; + case Reserveda: + debug << "Reserveda"; + break; + case Reservedb: + debug << "Reservedb"; + break; + case Reservedc: + debug << "Reservedc"; + break; + case Reservedd: + debug << "Reservedd"; + break; + case Reservedf: + debug << "Reservedf"; + break; + default: + debug << qPrintable(QString("0x%1").arg(character,0,16)); + break; + } + debug.setAutoInsertSpaces(insert_space); + return debug; +} +} diff --git a/yat/backend/controll_chars.h b/yat/backend/controll_chars.h new file mode 100644 index 0000000..b2b8bdc --- /dev/null +++ b/yat/backend/controll_chars.h @@ -0,0 +1,289 @@ +/************************************************************************************************** +* Copyright (c) 2012 Jørgen Lind +* +* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +* associated documentation files (the "Software"), to deal in the Software without restriction, +* including without limitation the rights to use, copy, modify, merge, publish, distribute, +* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all copies or +* substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT +* NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +* OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +***************************************************************************************************/ + +#ifndef CONTROLL_CHARS_H +#define CONTROLL_CHARS_H + +//This is taken largely from Standard ECMA-48 +//http://www.ecma-international.org/publications/standards/Ecma-048.htm +//Also to heres a few handy references +//http://invisible-island.net/xterm/ctlseqs/ctlseqs.html +//http://www.vt100.net/docs/vt100-ug/chapter3.html + +#include + +namespace C0 { +enum C0 { + NUL = 0x00, + SOH = 0x01, + STX = 0x02, + ETX = 0x03, + EOT = 0x04, + ENQ = 0x05, + ACK = 0x06, + BEL = 0x07, + BS = 0x08, + HT = 0x09, + LF = 0x0a, + VT = 0x0b, + FF = 0x0c, + CR = 0x0d, + SOorLS1 = 0x0e, + SIorLS0 = 0x0f, + DLE = 0x10, + DC1 = 0x11, + DC2 = 0x12, + DC3 = 0x13, + DC4 = 0x14, + NAK = 0x15, + SYN = 0x16, + ETB = 0x17, + CAN = 0x18, + EM = 0x19, + SUB = 0x1a, + ESC = 0x1b, + IS4 = 0x1c, + IS3 = 0x1d, + IS2 = 0x1e, + IS1 = 0x1f, + C0_END = 0x20 +}; +QDebug operator<<(QDebug debug, C0 character); +} + +namespace C1_7bit { +enum C1_7bit { + C1_7bit_Start = 0x80, + NOT_DEFINED = C1_7bit_Start, + NOT_DEFINED1 = 0x81, + BPH = 0x42, + NBH = 0x43, + NOT_DEFINED2 = 0x82, + NEL = 0x45, + SSA = 0x46, + ESA = 0x47, + HTS = 0x48, + HTJ = 0x49, + VTS = 0x4a, + PLD = 0x4b, + PLU = 0x4c, + RI = 0x4d, + SS2 = 0x4e, + SS3 = 0x4f, + DCS = 0x50, + PU1 = 0x51, + PU2 = 0x52, + STS = 0x53, + CCH = 0x54, + MW = 0x55, + SPA = 0x56, + EPA = 0x57, + SOS = 0x58, + NOT_DEFINED3 = 0x99, + SCI = 0x5a, + CSI = 0x5b, + ST = 0x5c, + OSC = 0x5d, + PM = 0x5e, + APC = 0x5f, + C1_7bit_Stop = 0x60 +}; +QDebug operator<<(QDebug debug, C1_7bit character); +} +namespace C1_8bit { +enum C1_8bit { + C1_8bit_Start = 0x80, + NOT_DEFINED = C1_8bit_Start, + NOT_DEFINED1 = 0x81, + BPH = 0x82, + NBH = 0x83, + NOT_DEFINED2 = 0x84, + NEL = 0x85, + SSA = 0x86, + ESA = 0x87, + HTS = 0x88, + HTJ = 0x89, + VTS = 0x8a, + PLD = 0x8b, + PLU = 0x8c, + RI = 0x8d, + SS2 = 0x8e, + SS3 = 0x8f, + DCS = 0x90, + PU1 = 0x91, + PU2C1_7bit = 0x92, + STS = 0x93, + CCH = 0x94, + MW = 0x95, + SPA = 0x96, + EPA = 0x97, + SOS = 0x98, + NOT_DEFINED3 = 0x99, + SCI = 0x9a, + CSI = 0x9b, + ST = 0x9c, + OSC = 0x9d, + PM = 0x9e, + APC = 0x9f, + C1_8bit_Stop = 0xa0 +}; +QDebug operator<<(QDebug debug, C1_8bit character); +} + +namespace FinalBytesNoIntermediate { +enum FinalBytesNoIntermediate { + ICH = 0x40, + CUU = 0x41, + CUD = 0x42, + CUF = 0x43, + CUB = 0x44, + CNL = 0x45, + CPL = 0x46, + CHA = 0x47, + CUP = 0x48, + CHT = 0x49, + ED = 0x4a, + EL = 0x4b, + IL = 0x4c, + DL = 0x4d, + EF = 0x4e, + EA = 0x4f, + DCH = 0x50, + SSE = 0x51, + CPR = 0x52, + SU = 0x53, + SD = 0x54, + NP = 0x55, + PP = 0x56, + CTC = 0x57, + ECH = 0x58, + CVT = 0x59, + CBT = 0x5a, + SRS = 0x5b, + PTX = 0x5c, + SDS = 0x5d, + SIMD = 0x5e, + NOT_DEFINED = 0x5f, + HPA = 0x60, + HPR = 0x61, + REP = 0x62, + DA = 0x63, + VPA = 0x64, + VPR = 0x65, + HVP = 0x66, + TBC = 0x67, + SM = 0x68, + MC = 0x69, + HPB = 0x6a, + VPB = 0x6b, + RM = 0x6c, + SGR = 0x6d, + DSR = 0x6e, + DAQ = 0x6f, + Reserved0 = 0x70, + Reserved1 = 0x71, + Reserved2 = 0x72, + Reserved3 = 0x73, + Reserved4 = 0x74, + Reserved5 = 0x75, + Reserved6 = 0x76, + Reserved7 = 0x77, + Reserved8 = 0x78, + Reserved9 = 0x79, + Reserveda = 0x7a, + Reservedb = 0x7b, + Reservedc = 0x7c, + Reservedd = 0x7d, + Reservede = 0x7e, + Reservedf = 0x7f +}; +QDebug operator<<(QDebug debug, FinalBytesNoIntermediate character); +} + +namespace FinalBytesSingleIntermediate { +enum FinalBytesSingleIntermediate { + SL = 0x40, + SR = 0x41, + GSM = 0x42, + GSS = 0x43, + FNT = 0x44, + TSS = 0x45, + JFY = 0x46, + SPI = 0x47, + QUAD = 0x48, + SSU = 0x49, + PFS = 0x4a, + SHS = 0x4b, + SVS = 0x4c, + IGS = 0x4d, + NOT_DEFINED = 0x4e, + IDCS = 0x4f, + PPA = 0x50, + PPR = 0x51, + PPB = 0x52, + SPD = 0x53, + DTA = 0x54, + SHL = 0x55, + SLL = 0x56, + FNK = 0x57, + SPQR = 0x58, + SEF = 0x59, + PEC = 0x5a, + SSW = 0x5b, + SACS = 0x5c, + SAPV = 0x5d, + STAB = 0x5e, + GCC = 0x5f, + TATE = 0x60, + TALE = 0x61, + TAC = 0x62, + TCC = 0x63, + TSR = 0x64, + SCO = 0x65, + SRCS = 0x66, + SCS = 0x67, + SLS = 0x68, + NOT_DEFINED2 = 0x69, + NOT_DEFINED3 = 0x6a, + SCP = 0x6b, + NOT_DEFINED4 = 0x6c, + NOT_DEFINED5 = 0x6d, + NOT_DEFINED6 = 0x6e, + NOT_DEFINED7 = 0x6f, + Reserved0 = 0x70, + Reserved1 = 0x71, + Reserved2 = 0x72, + Reserved3 = 0x73, + Reserved4 = 0x74, + Reserved5 = 0x75, + Reserved6 = 0x76, + Reserved7 = 0x77, + Reserved8 = 0x78, + Reserved9 = 0x79, + Reserveda = 0x7a, + Reservedb = 0x7b, + Reservedc = 0x7c, + Reservedd = 0x7d, + Reservedf = 0x7f +}; +QDebug operator<<(QDebug debug, FinalBytesSingleIntermediate character); +} + +#endif // CONTROLL_CHARS_H diff --git a/yat/backend/line.cpp b/yat/backend/line.cpp new file mode 100644 index 0000000..926719c --- /dev/null +++ b/yat/backend/line.cpp @@ -0,0 +1,437 @@ +/************************************************************************************************** +* Copyright (c) 2012 Jørgen Lind +* +* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +* associated documentation files (the "Software"), to deal in the Software without restriction, +* including without limitation the rights to use, copy, modify, merge, publish, distribute, +* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all copies or +* substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT +* NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +* OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +***************************************************************************************************/ + +#include "line.h" + +#include "text.h" +#include "screen.h" + +#include +#include + +#include + +#include + +QDebug operator<<(QDebug debug, TextStyleLine line) +{ + debug << "TextStyleLine: [" << line.start_index << ":" << line.end_index << "] : style:" << line.style; + return debug; +} + +Line::Line(Screen *screen) + : QObject(screen) + , m_screen(screen) + , m_index(0) + , m_old_index(-1) + , m_visible(true) + , m_changed(true) +{ + m_text_line.resize(screen->width()); + m_style_list.reserve(25); + + clear(); +} + +Line::~Line() +{ + releaseTextObjects(); +} + +Screen *Line::screen() const +{ + return m_screen; +} + +void Line::releaseTextObjects() +{ + m_changed = true; + for (int i = 0; i < m_style_list.size(); i++) { + if (m_style_list.at(i).text_segment) { + m_style_list.at(i).text_segment->setVisible(false); + delete m_style_list.at(i).text_segment; + m_style_list[i].text_segment = 0; + } + } +} + +void Line::clear() +{ + m_text_line.fill(QChar(' ')); + + for (int i = 0; i < m_style_list.size(); i++) { + if (m_style_list.at(i).text_segment) + releaseTextSegment(m_style_list.at(i).text_segment); + } + + m_style_list.clear(); + m_style_list.append(TextStyleLine(m_screen->defaultTextStyle(),0,m_text_line.size() -1)); + + m_changed = true; +} + +void Line::clearToEndOfLine(int index) +{ + m_changed = true; + + QString empty(m_text_line.size() - index, QChar(' ')); + m_text_line.replace(index, m_text_line.size()-index,empty); + bool found = false; + for (int i = 0; i < m_style_list.size(); i++) { + const TextStyleLine current_style = m_style_list.at(i); + if (found) { + if (current_style.text_segment) + releaseTextSegment(current_style.text_segment); + m_style_list.remove(i); + i--; + } else { + if (index <= current_style.end_index) { + found = true; + if (current_style.start_index == index) { + if (current_style.text_segment) + releaseTextSegment(current_style.text_segment); + m_style_list.remove(i); + i--; + } else { + m_style_list[i].end_index = index - 1; + m_style_list[i].text_dirty = true; + } + } + } + } + + if (m_style_list.size() && m_style_list.last().isCompatible(m_screen->defaultTextStyle())) { + m_style_list.last().end_index = m_text_line.size() -1; + } else { + m_style_list.append(TextStyleLine(m_screen->defaultTextStyle(),index, m_text_line.size() -1)); + } +} + +void Line::clearCharacters(int from, int to) +{ + QString empty(to-from, QChar(' ')); + const TextStyle &defaultTextStyle = m_screen->defaultTextStyle(); + replaceAtPos(from, empty, defaultTextStyle); +} + +void Line::deleteCharacters(int from, int to) +{ + m_changed = true; + + int removed = 0; + const int size = (to + 1) - from; + bool found = false; + + for (int i = 0; i < m_style_list.size(); i++) { + TextStyleLine ¤t_style = m_style_list[i]; + if (found) { + current_style.start_index -= removed; + current_style.end_index -= removed; + current_style.index_dirty = true; + if (removed != size) { + int current_style_size = current_style.end_index + 1 - current_style.start_index; + if (current_style_size <= size - removed) { + removed += current_style.end_index + 1 - current_style.start_index; + if (current_style.text_segment) + releaseTextSegment(current_style.text_segment); + m_style_list.remove(i); + i--; + } else { + current_style.end_index -= size - removed; + removed = size; + } + } + } else { + if (current_style.start_index <= from && current_style.end_index >= from) { + found = true; + int left_in_style = (current_style.end_index + 1) - from; + int subtract = std::min(left_in_style, size); + current_style.end_index -= subtract; + current_style.text_dirty = true; + removed = subtract; + if (current_style.end_index < current_style.start_index) { + if (current_style.text_segment) + releaseTextSegment(current_style.text_segment); + m_style_list.remove(i); + i--; + } + } + } + } + + TextStyle defaultStyle = m_screen->defaultTextStyle(); + if (m_style_list.last().isCompatible(defaultStyle)) { + m_style_list.last().end_index += size; + m_style_list.last().text_dirty = true; + } else { + m_style_list.append(TextStyleLine(defaultStyle, m_style_list.last().end_index + 1, + m_style_list.last().end_index + size)); + } + + m_text_line.remove(from, size); + QString empty(size,' '); + m_text_line.append(empty); +} + +void Line::setWidth(int width) +{ + bool emit_changed = m_text_line.size() != width; + if (m_text_line.size() > width) { + m_text_line.chop(m_text_line.size() - width); + } else if (m_text_line.size() < width) { + m_text_line.append(QString(width - m_text_line.size(), QChar(' '))); + } + + if (emit_changed) + emit widthChanged(); +} + +int Line::width() const +{ + return m_style_list.size(); +} + +void Line::replaceAtPos(int pos, const QString &text, const TextStyle &style) +{ + Q_ASSERT(pos + text.size() <= m_text_line.size()); + + m_changed = true; + + m_text_line.replace(pos,text.size(),text); + bool found = false; + for (int i = 0; i < m_style_list.size(); i++) { + TextStyleLine ¤t_style = m_style_list[i]; + if (found) { + if (current_style.end_index <= pos + text.size()) { + if (current_style.text_segment) + releaseTextSegment(current_style.text_segment); + m_style_list.remove(i); + i--; + } else if (current_style.start_index <= pos + text.size()) { + current_style.start_index = pos + text.size(); + current_style.style_dirty = true; + current_style.text_dirty = true; + current_style.index_dirty = true; + } else { + break; + } + } else if (pos >= current_style.start_index && pos <= current_style.end_index) { + found = true; + if (pos + text.size() -1 <= current_style.end_index) { + if (current_style.isCompatible(style)) { + current_style.text_dirty = true; + } else { + if (current_style.start_index == pos && current_style.end_index == pos + text.size() - 1) { + current_style.setStyle(style); + } else if (current_style.start_index == pos) { + current_style.start_index = pos + text.size(); + current_style.text_dirty = true; + m_style_list.insert(i, TextStyleLine(style,pos, pos+text.size() -1)); + } else if (current_style.end_index == pos + text.size()) { + current_style.end_index = pos - 1; + current_style.text_dirty = true; + m_style_list.insert(i+1, TextStyleLine(style,pos, pos+text.size())); + } else { + int old_end = current_style.end_index; + current_style.end_index = pos - 1; + current_style.text_dirty = true; + m_style_list.insert(i+1, TextStyleLine(style,pos, pos + text.size() - 1)); + if (pos + text.size() < m_text_line.size()) { + m_style_list.insert(i+2, TextStyleLine(current_style,pos + text.size(), old_end)); + } + } + } + break; + } else { + if (current_style.isCompatible(style)) { + current_style.end_index = pos + text.size() - 1; + current_style.text_dirty = true; + } else { + if (current_style.start_index == pos) { + current_style.end_index = pos + text.size() - 1; + current_style.style = style.style; + current_style.forground = style.forground; + current_style.background = style.background; + current_style.text_dirty = true; + current_style.style_dirty = true; + } else { + current_style.end_index = pos - 1; + current_style.text_dirty = true; + m_style_list.insert(i+1, TextStyleLine(style, pos, pos + text.size() -1)); + i++; + } + } + } + } + } +} + +void Line::insertAtPos(int pos, const QString &text, const TextStyle &style) +{ + m_changed = true; + + m_text_line.insert(pos,text); + m_text_line.chop(text.size()); + bool found = false; + + for (int i = 0; i < m_style_list.size(); i++) { + TextStyleLine ¤t_style = m_style_list[i]; + if (found) { + current_style.start_index += text.size(); + current_style.end_index += text.size(); + current_style.index_dirty = true; + if (current_style.start_index >= m_text_line.size()) { + releaseTextSegment(current_style.text_segment); + m_style_list.remove(i); + i--; + } else if (current_style.end_index >= m_text_line.size()) { + current_style.end_index = m_text_line.size()-1; + } + } else if (pos >= current_style.start_index && pos <= current_style.end_index) { + found = true; + if (current_style.start_index == pos) { + current_style.start_index += text.size(); + current_style.end_index += text.size(); + current_style.index_dirty = true; + m_style_list.insert(i, TextStyleLine(style, pos, pos+ text.size() - 1)); + i++; + } else if (current_style.end_index == pos) { + current_style.end_index--; + current_style.text_dirty = true; + m_style_list.insert(i+1, TextStyleLine(style, pos, pos+ text.size() - 1)); + i++; + } else { + int old_end = current_style.end_index; + current_style.end_index = pos -1; + current_style.text_dirty = true; + m_style_list.insert(i+1, TextStyleLine(style, pos, pos + text.size() - 1)); + if (pos + text.size() < m_text_line.size()) { + int segment_end = std::min(m_text_line.size() -1, old_end + text.size()); + m_style_list.insert(i+2, TextStyleLine(current_style, pos + text.size(), segment_end)); + i+=2; + } else { + i++; + } + } + } + } +} + +int Line::index() const +{ + return m_index; +} + +void Line::setIndex(int index) +{ + m_index = index; +} + +QString *Line::textLine() +{ + return &m_text_line; +} + +void Line::setVisible(bool visible) +{ + if (visible != m_visible) { + m_visible = visible; + emit visibleChanged(); + } +} + +bool Line::visible() const +{ + return m_visible; +} + +void Line::dispatchEvents() +{ + if (m_index != m_old_index) { + m_old_index = m_index; + emit indexChanged(); + } + + if (!m_changed) { + return; + } + + for (int i = 0; i < m_style_list.size(); i++) { + TextStyleLine ¤t_style = m_style_list[i]; + + if (current_style.text_segment == 0) { + current_style.text_segment = createTextSegment(current_style); + } + + if (current_style.style_dirty) { + current_style.text_segment->setTextStyle(current_style); + current_style.style_dirty = false; + } + + if (current_style.index_dirty || current_style.text_dirty) { + current_style.text_segment->setStringSegment(current_style.start_index, current_style.end_index, current_style.text_dirty); + current_style.index_dirty = false; + current_style.text_dirty = false; + } + + m_style_list.at(i).text_segment->dispatchEvents(); + } + + m_changed = false; + + for (int i = 0; i< m_to_delete.size(); i++) { + delete m_to_delete[i]; + } + m_to_delete.clear(); +} + +QVector Line::style_list() +{ + return m_style_list; +} + +Text *Line::createTextSegment(const TextStyleLine &style_line) +{ + Text *to_return; + if (m_to_delete.size()) { + to_return = m_to_delete.takeLast(); + } else { + to_return = new Text(screen()); + to_return->setLine(this); + emit textCreated(to_return); + } + + to_return->setVisible(true); + + return to_return; +} + +void Line::releaseTextSegment(Text *text) +{ + text->setVisible(false); + m_to_delete.append(text); +} + +void Line::printStyleList() const +{ + for (int i= 0; i < m_style_list.size(); i++) { + qDebug() << "i" << m_style_list.at(i); + } +} diff --git a/yat/backend/line.h b/yat/backend/line.h new file mode 100644 index 0000000..f0a2de4 --- /dev/null +++ b/yat/backend/line.h @@ -0,0 +1,137 @@ +/************************************************************************************************** +* Copyright (c) 2012 Jørgen Lind +* +* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +* associated documentation files (the "Software"), to deal in the Software without restriction, +* including without limitation the rights to use, copy, modify, merge, publish, distribute, +* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all copies or +* substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT +* NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +* OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +***************************************************************************************************/ + +#ifndef TEXT_SEGMENT_LINE_H +#define TEXT_SEGMENT_LINE_H + +#include + +#include "text.h" + +class Screen; +class QQuickItem; + +class TextStyleLine : public TextStyle { +public: + TextStyleLine(const TextStyle &style, int start_index, int end_index) + : TextStyle(style) + , start_index(start_index) + , end_index(end_index) + , old_index(-1) + , text_segment(0) + , style_dirty(true) + , index_dirty(true) + , text_dirty(true) + { + } + + TextStyleLine() + : start_index(0) + , end_index(0) + , old_index(-1) + , text_segment(0) + , style_dirty(false) + , index_dirty(false) + , text_dirty(false) + { + + } + + int start_index; + int end_index; + + int old_index; + Text *text_segment; + bool style_dirty; + bool index_dirty; + bool text_dirty; + + void setStyle(const TextStyle &style) { + forground = style.forground; + background = style.background; + this->style = style.style; + } +}; +QDebug operator<<(QDebug debug, TextStyleLine line); + +class Line : public QObject +{ + Q_OBJECT + + Q_PROPERTY(int index READ index NOTIFY indexChanged) + Q_PROPERTY(Screen *screen READ screen CONSTANT) + Q_PROPERTY(bool visible READ visible WRITE setVisible NOTIFY visibleChanged) + Q_PROPERTY(int width READ width WRITE setWidth NOTIFY widthChanged) +public: + Line(Screen *screen); + ~Line(); + + Q_INVOKABLE Screen *screen() const; + + void releaseTextObjects(); + + void clear(); + void clearToEndOfLine(int index); + void clearCharacters(int from, int to); + void deleteCharacters(int from, int to); + + void setWidth(int width); + int width() const; + + void replaceAtPos(int i, const QString &text, const TextStyle &style); + void insertAtPos(int i, const QString &text, const TextStyle &style); + + int index() const; + void setIndex(int index); + + QString *textLine(); + + void setVisible(bool visible); + bool visible() const; + + void dispatchEvents(); + + QVector style_list(); + + void printStyleList() const; +signals: + void indexChanged(); + void visibleChanged(); + void widthChanged(); + + void textCreated(Text *text); +private: + Text *createTextSegment(const TextStyleLine &style_line); + void releaseTextSegment(Text *text); + + Screen *m_screen; + QString m_text_line; + QVector m_style_list; + int m_index; + int m_old_index; + + bool m_visible; + QVector m_to_delete; + bool m_changed; + + bool m_delete_handle; +}; + +#endif // TEXT_SEGMENT_LINE_H diff --git a/yat/backend/main.cpp b/yat/backend/main.cpp new file mode 100644 index 0000000..1b09d79 --- /dev/null +++ b/yat/backend/main.cpp @@ -0,0 +1,32 @@ +/************************************************************************************************** +* Copyright (c) 2012 Jørgen Lind +* +* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +* associated documentation files (the "Software"), to deal in the Software without restriction, +* including without limitation the rights to use, copy, modify, merge, publish, distribute, +* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all copies or +* substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT +* NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +* OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +***************************************************************************************************/ + +#include "terminal_state.h" + +#include + +int main(int argc, char *argv[]) +{ + QGuiApplication app(argc, argv); + + TerminalState state; + + return app.exec(); +} diff --git a/yat/backend/parser.cpp b/yat/backend/parser.cpp new file mode 100644 index 0000000..5354f51 --- /dev/null +++ b/yat/backend/parser.cpp @@ -0,0 +1,793 @@ +/************************************************************************************************** +* Copyright (c) 2012 Jørgen Lind +* +* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +* associated documentation files (the "Software"), to deal in the Software without restriction, +* including without limitation the rights to use, copy, modify, merge, publish, distribute, +* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all copies or +* substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT +* NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +* OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +***************************************************************************************************/ + +#include "parser.h" + +#include "controll_chars.h" +#include "screen.h" + +#include + + +static bool yat_parser_debug = qEnvironmentVariableIsSet("YAT_PARSER_DEBUG"); + +Parser::Parser(Screen *screen) + : m_decode_state(PlainText) + , m_current_token_start(0) + , m_currrent_position(0) + , m_intermediate_char(QChar()) + , m_parameters(10) + , m_screen(screen) +{ +} + +void Parser::addData(const QByteArray &data) +{ + m_current_token_start = 0; + m_current_data = data; + for (m_currrent_position = 0; m_currrent_position < data.size(); m_currrent_position++) { + uchar character = data.at(m_currrent_position); + switch (m_decode_state) { + case PlainText: + //UTF-8 + if (character > 127) + continue; + if (character < C0::C0_END || + (character >= C1_8bit::C1_8bit_Start && + character <= C1_8bit::C1_8bit_Stop)) { + if (m_currrent_position != m_current_token_start) { + m_screen->replaceAtCursor(QString::fromUtf8(data.mid(m_current_token_start, + m_currrent_position - m_current_token_start))); + tokenFinished(); + m_current_token_start--; + } + m_decode_state = DecodeC0; + decodeC0(data.at(m_currrent_position)); + } + break; + case DecodeC0: + decodeC0(character); + break; + case DecodeC1_7bit: + decodeC1_7bit(character); + break; + case DecodeCSI: + decodeCSI(character); + break; + case DecodeOSC: + decodeOSC(character); + break; + case DecodeOtherEscape: + decodeOtherEscape(character); + break; + } + + } + if (m_decode_state == PlainText) { + QByteArray text = data.mid(m_current_token_start); + if (text.size()) { + m_screen->replaceAtCursor(QString::fromUtf8(text)); + tokenFinished(); + } + } + m_current_data = QByteArray(); +} + +void Parser::decodeC0(uchar character) +{ + if (yat_parser_debug) + qDebug() << C0::C0(character); + switch (character) { + case C0::NUL: + case C0::SOH: + case C0::STX: + case C0::ETX: + case C0::EOT: + case C0::ENQ: + case C0::ACK: + qDebug() << "Unhandled" << C0::C0(character); + tokenFinished(); + break; + case C0::BEL: + m_screen->scheduleFlash(); + tokenFinished(); + break; + case C0::BS: + m_screen->backspace(); + tokenFinished(); + break; + case C0::HT: { + int x = m_screen->cursorPosition().x(); + int spaces = 8 - (x % 8); + m_screen->replaceAtCursor(QString(spaces,' ')); + } + tokenFinished(); + break; + case C0::LF: + m_screen->lineFeed(); + tokenFinished(); + break; + case C0::VT: + case C0::FF: + qDebug() << "Unhandled" << C0::C0(character); + tokenFinished(); + break; + case C0::CR: + m_screen->moveCursorHome(); + tokenFinished(); + //next should be a linefeed; + break; + case C0::SOorLS1: + case C0::SIorLS0: + case C0::DLE: + case C0::DC1: + case C0::DC2: + case C0::DC3: + case C0::DC4: + case C0::NAK: + case C0::SYN: + case C0::ETB: + case C0::CAN: + case C0::EM: + case C0::SUB: + qDebug() << "Unhandled" << C0::C0(character); + tokenFinished(); + break; + case C0::ESC: + m_decode_state = DecodeC1_7bit; + break; + case C0::IS4: + case C0::IS3: + case C0::IS2: + case C0::IS1: + default: + qDebug() << "Unhandled" << C0::C0(character); + tokenFinished(); + break; + } +} + +void Parser::decodeC1_7bit(uchar character) +{ + if (yat_parser_debug) + qDebug() << C1_7bit::C1_7bit(character); + switch(character) { + case C1_7bit::CSI: + m_decode_state = DecodeCSI; + break; + case C1_7bit::OSC: + m_decode_state = DecodeOSC; + break; + case C1_7bit::RI: + m_screen->reverseLineFeed(); + tokenFinished(); + break; + case '%': + case '#': + case '(': + m_parameters.append(-character); + m_decode_state = DecodeOtherEscape; + break; + case '=': + qDebug() << "Application keypad"; + tokenFinished(); + break; + case '>': + qDebug() << "Normal keypad mode"; + tokenFinished(); + break; + default: + qDebug() << "Unhandled" << C1_7bit::C1_7bit(character); + tokenFinished(); + } +} + +void Parser::decodeParameters(uchar character) +{ + switch (character) { + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + case 0x38: + case 0x39: + m_parameter_string.append(character); + break; + case 0x3a: + qDebug() << "Encountered special delimiter in parameterbyte"; + break; + case 0x3b: + appendParameter(); + break; + case 0x3c: + case 0x3d: + case 0x3e: + case 0x3f: + appendParameter(); + m_parameters.append(-character); + break; + default: + //this is undefined for now + qDebug() << "Encountered undefined parameter byte"; + break; + } +} + +void Parser::decodeCSI(uchar character) +{ + if (character >= 0x30 && character <= 0x3f) { + decodeParameters(character); + } else { + if (character >= 0x20 && character <= 0x2f) { + if (m_intermediate_char.unicode()) + qDebug() << "Warning!: double intermediate bytes found in CSI"; + m_intermediate_char = character; + } else if (character >= 0x40 && character <= 0x7d) { + if (m_intermediate_char.unicode()) { + if (yat_parser_debug) + qDebug() << FinalBytesSingleIntermediate::FinalBytesSingleIntermediate(character); + switch (character) { + case FinalBytesSingleIntermediate::SL: + case FinalBytesSingleIntermediate::SR: + case FinalBytesSingleIntermediate::GSM: + case FinalBytesSingleIntermediate::GSS: + case FinalBytesSingleIntermediate::FNT: + case FinalBytesSingleIntermediate::TSS: + case FinalBytesSingleIntermediate::JFY: + case FinalBytesSingleIntermediate::SPI: + case FinalBytesSingleIntermediate::QUAD: + case FinalBytesSingleIntermediate::SSU: + case FinalBytesSingleIntermediate::PFS: + case FinalBytesSingleIntermediate::SHS: + case FinalBytesSingleIntermediate::SVS: + case FinalBytesSingleIntermediate::IGS: + case FinalBytesSingleIntermediate::IDCS: + case FinalBytesSingleIntermediate::PPA: + case FinalBytesSingleIntermediate::PPR: + case FinalBytesSingleIntermediate::PPB: + case FinalBytesSingleIntermediate::SPD: + case FinalBytesSingleIntermediate::DTA: + case FinalBytesSingleIntermediate::SHL: + case FinalBytesSingleIntermediate::SLL: + case FinalBytesSingleIntermediate::FNK: + case FinalBytesSingleIntermediate::SPQR: + case FinalBytesSingleIntermediate::SEF: + case FinalBytesSingleIntermediate::PEC: + case FinalBytesSingleIntermediate::SSW: + case FinalBytesSingleIntermediate::SACS: + case FinalBytesSingleIntermediate::SAPV: + case FinalBytesSingleIntermediate::STAB: + case FinalBytesSingleIntermediate::GCC: + case FinalBytesSingleIntermediate::TATE: + case FinalBytesSingleIntermediate::TALE: + case FinalBytesSingleIntermediate::TAC: + case FinalBytesSingleIntermediate::TCC: + case FinalBytesSingleIntermediate::TSR: + case FinalBytesSingleIntermediate::SCO: + case FinalBytesSingleIntermediate::SRCS: + case FinalBytesSingleIntermediate::SCS: + case FinalBytesSingleIntermediate::SLS: + case FinalBytesSingleIntermediate::SCP: + default: + qDebug() << "unhandled CSI" << FinalBytesSingleIntermediate::FinalBytesSingleIntermediate(character); + tokenFinished(); + break; + } + } else { + if (yat_parser_debug) + qDebug() << FinalBytesNoIntermediate::FinalBytesNoIntermediate(character); + switch (character) { + case FinalBytesNoIntermediate::ICH: { + appendParameter(); + int n_chars = m_parameters.size() ? m_parameters.at(0) : 1; + qDebug() << "ICH WITH n_chars" << n_chars; + m_screen->insertEmptyCharsAtCursor(n_chars); + tokenFinished(); + } + break; + case FinalBytesNoIntermediate::CUU: { + appendParameter(); + Q_ASSERT(m_parameters.size() < 2); + int move_up = m_parameters.size() ? m_parameters.at(0) : 1; + m_screen->moveCursorUp(move_up); + tokenFinished(); + } + break; + case FinalBytesNoIntermediate::CUD: + tokenFinished(); + qDebug() << "unhandled CSI" << FinalBytesNoIntermediate::FinalBytesNoIntermediate(character); + break; + case FinalBytesNoIntermediate::CUF:{ + appendParameter(); + Q_ASSERT(m_parameters.size() < 2); + int move_right = m_parameters.size() ? m_parameters.at(0) : 1; + m_screen->moveCursorRight(move_right); + tokenFinished(); + } + break; + case FinalBytesNoIntermediate::CUB: + case FinalBytesNoIntermediate::CNL: + case FinalBytesNoIntermediate::CPL: + qDebug() << "unhandled CSI" << FinalBytesNoIntermediate::FinalBytesNoIntermediate(character); + tokenFinished(); + break; + case FinalBytesNoIntermediate::CHA: { + appendParameter(); + Q_ASSERT(m_parameters.size() < 2); + int move_to_pos_on_line = m_parameters.size() ? m_parameters.at(0) : 1; + m_screen->moveCursorToCharacter(move_to_pos_on_line); + } + tokenFinished(); + break; + case FinalBytesNoIntermediate::CUP: + appendParameter(); + if (!m_parameters.size()) { + m_screen->moveCursorTop(); + m_screen->moveCursorHome(); + } else if (m_parameters.size() == 2){ + m_screen->moveCursor(m_parameters.at(1), m_parameters.at(0)); + } else { + qDebug() << "OHOHOHOH"; + } + tokenFinished(); + break; + case FinalBytesNoIntermediate::CHT: + tokenFinished(); + qDebug() << "unhandled CSI" << FinalBytesNoIntermediate::FinalBytesNoIntermediate(character); + break; + case FinalBytesNoIntermediate::ED: + appendParameter(); + if (!m_parameters.size()) { + m_screen->eraseFromCurrentLineToEndOfScreen(); + } else { + switch (m_parameters.at(0)) { + case 1: + m_screen->eraseFromCurrentLineToBeginningOfScreen(); + break; + case 2: + m_screen->eraseScreen(); + break; + default: + qDebug() << "Invalid parameter value for FinalBytesNoIntermediate::ED"; + } + } + + tokenFinished(); + break; + case FinalBytesNoIntermediate::EL: + appendParameter(); + if (!m_parameters.size() || m_parameters.at(0) == 0) { + m_screen->eraseFromCursorPositionToEndOfLine(); + } else if (m_parameters.at(0) == 1) { + m_screen->eraseToCursorPosition(); + } else if (m_parameters.at(0) == 2) { + m_screen->eraseLine(); + } else{ + qDebug() << "Fault when processing FinalBytesNoIntermediate::EL"; + } + tokenFinished(); + break; + case FinalBytesNoIntermediate::IL: { + appendParameter(); + int count = 1; + if (m_parameters.size()) { + count = m_parameters.at(0); + } + m_screen->insertLines(count); + tokenFinished(); + } + break; + case FinalBytesNoIntermediate::DL: { + appendParameter(); + int count = 1; + if (m_parameters.size()) { + count = m_parameters.at(0); + } + m_screen->deleteLines(count); + tokenFinished(); + } + break; + case FinalBytesNoIntermediate::EF: + case FinalBytesNoIntermediate::EA: + qDebug() << "unhandled CSI" << FinalBytesNoIntermediate::FinalBytesNoIntermediate(character); + tokenFinished(); + break; + case FinalBytesNoIntermediate::DCH:{ + appendParameter(); + Q_ASSERT(m_parameters.size() < 2); + int n_chars = m_parameters.size() ? m_parameters.at(0) : 1; + m_screen->deleteCharacters(n_chars); + } + tokenFinished(); + break; + case FinalBytesNoIntermediate::SSE: + case FinalBytesNoIntermediate::CPR: + case FinalBytesNoIntermediate::SU: + case FinalBytesNoIntermediate::SD: + case FinalBytesNoIntermediate::NP: + case FinalBytesNoIntermediate::PP: + case FinalBytesNoIntermediate::CTC: + case FinalBytesNoIntermediate::ECH: + case FinalBytesNoIntermediate::CVT: + case FinalBytesNoIntermediate::CBT: + case FinalBytesNoIntermediate::SRS: + case FinalBytesNoIntermediate::PTX: + case FinalBytesNoIntermediate::SDS: + case FinalBytesNoIntermediate::SIMD: + case FinalBytesNoIntermediate::HPA: + case FinalBytesNoIntermediate::HPR: + case FinalBytesNoIntermediate::REP: + qDebug() << "unhandled CSI" << FinalBytesNoIntermediate::FinalBytesNoIntermediate(character); + tokenFinished(); + break; + case FinalBytesNoIntermediate::DA: + appendParameter(); + if (m_parameters.size()) { + switch (m_parameters.at(0)) { + case -'>': + m_screen->sendSecondaryDA(); + break; + case -'?': + qDebug() << "WHAT!!!"; + break; //ignore + case 0: + default: + m_screen->sendPrimaryDA(); + } + } else { + m_screen->sendPrimaryDA(); + } + tokenFinished(); + break; + case FinalBytesNoIntermediate::VPA: { + appendParameter(); + Q_ASSERT(m_parameters.size() < 2); + int move_to_line = m_parameters.size() ? m_parameters.at(0) : 1; + m_screen->moveCursorToLine(move_to_line); + } + tokenFinished(); + break; + case FinalBytesNoIntermediate::VPR: + case FinalBytesNoIntermediate::HVP: + case FinalBytesNoIntermediate::TBC: + qDebug() << "unhandled CSI" << FinalBytesNoIntermediate::FinalBytesNoIntermediate(character); + tokenFinished(); + break; + case FinalBytesNoIntermediate::SM: + appendParameter(); + if (m_parameters.size() && m_parameters.at(0) == -'?') { + if (m_parameters.size() > 1) { + switch (m_parameters.at(1)) { + case 1: + m_screen->setApplicationCursorKeysMode(true); + break; + case 4: + qDebug() << "Insertion mode"; + break; + case 7: + qDebug() << "MODE 7"; + break; + case 12: + m_screen->setCursorBlinking(true); + break; + case 25: + m_screen->setCursorVisible(true); + break; + case 1034: + //I don't know what this sequence is + break; + case 1049: + m_screen->saveCursor(); + m_screen->saveScreenData(); + break; + default: + qDebug() << "unhandled CSI FinalBytesNoIntermediate::SM ? with parameter:" << m_parameters.at(1); + } + } else { + qDebug() << "unhandled CSI FinalBytesNoIntermediate::SM ?"; + } + } else { + qDebug() << "unhandled CSI FinalBytesNoIntermediate::SM"; + } + tokenFinished(); + break; + case FinalBytesNoIntermediate::MC: + case FinalBytesNoIntermediate::HPB: + case FinalBytesNoIntermediate::VPB: + qDebug() << "unhandled CSI" << FinalBytesNoIntermediate::FinalBytesNoIntermediate(character); + tokenFinished(); + break; + case FinalBytesNoIntermediate::RM: + appendParameter(); + if (m_parameters.size()) { + switch(m_parameters.at(0)) { + case -'?': + if (m_parameters.size() > 1) { + switch(m_parameters.at(1)) { + case 1: + qDebug() << "Normal cursor keys"; + break; + case 12: + m_screen->setCursorBlinking(false); + break; + case 25: + m_screen->setCursorVisible(false); + break; + case 1049: + m_screen->restoreCursor(); + m_screen->restoreScreenData(); + break; + default: + qDebug() << "unhandled CSI FinalBytesNoIntermediate::RM? with " + "parameter " << m_parameters.at(1); + } + } else { + qDebug() << "unhandled CSI FinalBytesNoIntermediate::RM"; + } + break; + case 4: + m_screen->setInsertMode(Screen::Replace); + default: + qDebug() << "unhandled CSI FinalBytesNoIntermediate::RM"; + break; + } + } + tokenFinished(); + break; + case FinalBytesNoIntermediate::SGR: { + appendParameter(); + + if (!m_parameters.size()) + m_parameters << 0; + + for (int i = 0; i < m_parameters.size();i++) { + switch(m_parameters.at(i)) { + case 0: + // m_screen->setTextStyle(TextStyle::Normal); + m_screen->resetStyle(); + break; + case 1: + m_screen->setTextStyle(TextStyle::Bold); + break; + case 5: + m_screen->setTextStyle(TextStyle::Blinking); + break; + case 7: + m_screen->setTextStyle(TextStyle::Inverse); + break; + case 8: + qDebug() << "SGR: Hidden text not supported"; + break; + case 22: + m_screen->setTextStyle(TextStyle::Normal); + break; + case 24: + m_screen->setTextStyle(TextStyle::Underlined, false); + break; + case 25: + m_screen->setTextStyle(TextStyle::Blinking, false); + break; + case 27: + m_screen->setTextStyle(TextStyle::Inverse, false); + break; + case 28: + qDebug() << "SGR: Visible text is allways on"; + break; + case 30: + case 31: + case 32: + case 33: + case 34: + case 35: + case 36: + case 37: + // case 38: + case 39: + case 40: + case 41: + case 42: + case 43: + case 44: + case 45: + case 46: + case 47: + // case 38: + case 49: + m_screen->setTextStyleColor(m_parameters.at(i)); + break; + + + + + default: + qDebug() << "Unknown SGR" << m_parameters.at(i); + } + } + + tokenFinished(); + } + break; + case FinalBytesNoIntermediate::DSR: + qDebug() << "report"; + case FinalBytesNoIntermediate::DAQ: + case FinalBytesNoIntermediate::Reserved0: + case FinalBytesNoIntermediate::Reserved1: + qDebug() << "Unhandeled CSI" << FinalBytesNoIntermediate::FinalBytesNoIntermediate(character); + tokenFinished(); + break; + case FinalBytesNoIntermediate::Reserved2: + appendParameter(); + if (m_parameters.size() == 2) { + if (m_parameters.at(0) >= 0) { + m_screen->setScrollArea(m_parameters.at(0),m_parameters.at(1)); + } else { + qDebug() << "Unknown value for scrollRegion"; + } + } else { + qDebug() << "Unknown parameterset for scrollRegion"; + } + tokenFinished(); + break; + case FinalBytesNoIntermediate::Reserved3: + case FinalBytesNoIntermediate::Reserved4: + case FinalBytesNoIntermediate::Reserved5: + case FinalBytesNoIntermediate::Reserved6: + case FinalBytesNoIntermediate::Reserved7: + case FinalBytesNoIntermediate::Reserved8: + case FinalBytesNoIntermediate::Reserved9: + case FinalBytesNoIntermediate::Reserveda: + case FinalBytesNoIntermediate::Reservedb: + case FinalBytesNoIntermediate::Reservedc: + case FinalBytesNoIntermediate::Reservedd: + case FinalBytesNoIntermediate::Reservede: + case FinalBytesNoIntermediate::Reservedf: + default: + qDebug() << "Unhandeled CSI" << FinalBytesNoIntermediate::FinalBytesNoIntermediate(character); + tokenFinished(); + break; + } + } + } + } +} + +void Parser::decodeOSC(uchar character) +{ + if (!m_parameters.size() && + character >= 0x30 && character <= 0x3f) { + decodeParameters(character); + } else { + if (m_decode_osc_state == None) { + appendParameter(); + if (m_parameters.size() != 1) { + tokenFinished(); + return; + } + + switch (m_parameters.at(0)) { + case 0: + m_decode_osc_state = ChangeWindowAndIconName; + break; + case 1: + m_decode_osc_state = ChangeIconTitle; + break; + case 2: + m_decode_osc_state = ChangeWindowTitle; + break; + default: + m_decode_osc_state = Unknown; + break; + } + } else { + if (character == 0x07) { + if (m_decode_osc_state == ChangeWindowAndIconName || + m_decode_osc_state == ChangeWindowTitle) { + QString title = QString::fromUtf8(m_current_data.mid(m_current_token_start+4, + m_currrent_position - m_current_token_start -1)); + m_screen->setTitle(title); + } + tokenFinished(); + } + } + } +} + +void Parser::decodeOtherEscape(uchar character) +{ + Q_ASSERT(m_parameters.size()); + switch(m_parameters.at(0)) { + case -'(': + switch(character) { + case 0: + m_screen->setCharacterMap("DEC Special Character and Line Drawing Set"); + break; + case 'A': + m_screen->setCharacterMap("UK"); + break; + case 'B': + m_screen->setCharacterMap("USASCII"); + break; + case '4': + m_screen->setCharacterMap("Dutch"); + break; + case 'C': + case '5': + m_screen->setCharacterMap("Finnish"); + break; + case 'R': + m_screen->setCharacterMap("French"); + break; + case 'Q': + m_screen->setCharacterMap("FrenchCanadian"); + break; + case 'K': + m_screen->setCharacterMap("German"); + break; + case 'Y': + m_screen->setCharacterMap("Italian"); + break; + case 'E': + case '6': + m_screen->setCharacterMap("NorDan"); + break; + case 'Z': + m_screen->setCharacterMap("Spanish"); + break; + case 'H': + case '7': + m_screen->setCharacterMap("Sweedish"); + break; + case '=': + m_screen->setCharacterMap("Swiss"); + break; + default: + qDebug() << "Not supported Character set!"; + } + break; + default: + qDebug() << "Other Escape sequence not recognized"; + } + tokenFinished(); +} + +void Parser::tokenFinished() +{ + m_decode_state = PlainText; + m_decode_osc_state = None; + + m_parameters.clear(); + m_parameter_string.clear(); + + m_current_token_start = m_currrent_position + 1; + m_intermediate_char = 0; +} + +void Parser::appendParameter() +{ + if (m_parameter_string.size()) { + m_parameters.append(m_parameter_string.toUShort()); + m_parameter_string.clear(); + } +} + diff --git a/yat/backend/parser.h b/yat/backend/parser.h new file mode 100644 index 0000000..f00bba6 --- /dev/null +++ b/yat/backend/parser.h @@ -0,0 +1,83 @@ +/************************************************************************************************** +* Copyright (c) 2012 Jørgen Lind +* +* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +* associated documentation files (the "Software"), to deal in the Software without restriction, +* including without limitation the rights to use, copy, modify, merge, publish, distribute, +* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all copies or +* substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT +* NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +* OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +***************************************************************************************************/ + +#ifndef PARSER_H +#define PARSER_H + +#include +#include +#include + +#include "text.h" + +class Parser +{ +public: + Parser(Screen *screen); + + void addData(const QByteArray &data); + +private: + + enum DecodeState { + PlainText, + DecodeC0, + DecodeC1_7bit, + DecodeCSI, + DecodeOSC, + DecodeOtherEscape + }; + + enum DecodeOSCState { + None, + ChangeWindowAndIconName, + ChangeIconTitle, + ChangeWindowTitle, + Unknown + }; + + void decodeC0(uchar character); + void decodeC1_7bit(uchar character); + void decodeParameters(uchar character); + void decodeCSI(uchar character); + void decodeOSC(uchar character); + void decodeOtherEscape(uchar character); + + void tokenFinished(); + + void appendParameter(); + + DecodeState m_decode_state; + DecodeOSCState m_decode_osc_state; + + QByteArray m_current_data; + + int m_current_token_start; + int m_currrent_position; + + QChar m_intermediate_char; + + QByteArray m_parameter_string; + QVector m_parameters; + + Screen *m_screen; +}; + +#endif // PARSER_H diff --git a/yat/backend/screen.cpp b/yat/backend/screen.cpp new file mode 100644 index 0000000..fe88d66 --- /dev/null +++ b/yat/backend/screen.cpp @@ -0,0 +1,958 @@ +/************************************************************************************************** +* Copyright (c) 2012 Jørgen Lind +* +* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +* associated documentation files (the "Software"), to deal in the Software without restriction, +* including without limitation the rights to use, copy, modify, merge, publish, distribute, +* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all copies or +* substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT +* NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +* OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +***************************************************************************************************/ + +#include "screen.h" + +#include "line.h" + +#include "controll_chars.h" + +#include +#include +#include + +#include +#include +#include + +#include + +#include + +Screen::Screen(QObject *parent) + : QObject(parent) + , m_parser(this) + , m_timer_event_id(0) + , m_cursor_visible(true) + , m_cursor_visible_changed(false) + , m_cursor_blinking(true) + , m_cursor_blinking_changed(false) + , m_insert_mode(Replace) + , m_selection_valid(false) + , m_selection_moved(0) + , m_flash(false) + , m_cursor_changed(false) + , m_reset(false) + , m_application_cursor_key_mode(false) +{ + connect(&m_pty, &YatPty::readyRead, this, &Screen::readData); + + m_screen_stack.reserve(2); + + m_cursor_stack << QPoint(0,0); + + m_current_text_style.style = TextStyle::Normal; + m_current_text_style.forground = ColorPalette::DefaultForground; + m_current_text_style.background = ColorPalette::DefaultBackground; + + connect(&m_pty, SIGNAL(hangupReceived()),qGuiApp, SLOT(quit())); +} + +Screen::~Screen() +{ + for (int i = 0; i < m_screen_stack.size(); i++) { + delete m_screen_stack.at(i); + + } +} + + +QColor Screen::screenBackground() +{ + return QColor(Qt::black); +} + +QColor Screen::defaultForgroundColor() const +{ + return m_palette.normalColor(ColorPalette::DefaultForground); +} + +QColor Screen::defaultBackgroundColor() const +{ + return QColor(Qt::transparent); +} + +void Screen::setHeight(int height) +{ + if (!m_screen_stack.size()) { + m_screen_stack << new ScreenData(this); + } + + ScreenData *data = current_screen_data(); + int size_difference = data->height() - height; + + if (!size_difference) + return; + + data->setHeight(height); + + if (size_difference > 0) { + if (current_cursor_y() > 0) + current_cursor_pos().ry()--; + } + + m_pty.setHeight(height, height * 10); + dispatchChanges(); +} + +void Screen::setWidth(int width) +{ + if (!m_screen_stack.size()) + m_screen_stack << new ScreenData(this); + + current_screen_data()->setWidth(width); + m_pty.setWidth(width, width * 10); + +} + +int Screen::width() const +{ + return m_pty.size().width(); +} + +void Screen::saveScreenData() +{ + ScreenData *new_data = new ScreenData(this); + QSize pty_size = m_pty.size(); + new_data->setHeight(pty_size.height()); + new_data->setWidth(pty_size.width()); + + for (int i = 0; i < new_data->height(); i++) { + current_screen_data()->at(i)->setVisible(false); + } + + m_screen_stack << new_data; + + setSelectionEnabled(false); + +} + +void Screen::restoreScreenData() +{ + ScreenData *data = current_screen_data(); + m_screen_stack.remove(m_screen_stack.size()-1); + delete data; + + QSize pty_size = m_pty.size(); + current_screen_data()->setHeight(pty_size.height()); + current_screen_data()->setWidth(pty_size.width()); + + for (int i = 0; i < current_screen_data()->height(); i++) { + current_screen_data()->at(i)->setVisible(true); + } + + setSelectionEnabled(false); +} + +int Screen::height() const +{ + return current_screen_data()->height(); +} + +void Screen::setInsertMode(InsertMode mode) +{ + m_insert_mode = mode; +} + +void Screen::setTextStyle(TextStyle::Style style, bool add) +{ + if (add) { + m_current_text_style.style |= style; + } else { + m_current_text_style.style &= !style; + } +} + +void Screen::resetStyle() +{ + m_current_text_style.background = ColorPalette::DefaultBackground; + m_current_text_style.forground = ColorPalette::DefaultForground; + m_current_text_style.style = TextStyle::Normal; +} + +TextStyle Screen::currentTextStyle() const +{ + return m_current_text_style; +} + +TextStyle Screen::defaultTextStyle() const +{ + TextStyle style; + style.style = TextStyle::Normal; + style.forground = ColorPalette::DefaultForground; + style.background = ColorPalette::DefaultBackground; + return style; +} + +QPoint Screen::cursorPosition() const +{ + return QPoint(current_cursor_x(),current_cursor_y()); +} + +void Screen::moveCursorHome() +{ + current_cursor_pos().setX(0); + m_cursor_changed = true; +} + +void Screen::moveCursorTop() +{ + current_cursor_pos().setY(0); + m_cursor_changed = true; +} + +void Screen::moveCursorUp(int n_positions) +{ + if (!current_cursor_pos().y()) + return; + + if (n_positions <= current_cursor_pos().y()) { + current_cursor_pos().ry() -= n_positions; + } else { + current_cursor_pos().ry() = 0; + } + m_cursor_changed = true; +} + +void Screen::moveCursorDown() +{ + current_cursor_pos().ry() += 1; + m_cursor_changed = true; +} + +void Screen::moveCursorLeft() +{ + current_cursor_pos().rx() -= 1; + m_cursor_changed = true; +} + +void Screen::moveCursorRight(int n_positions) +{ + current_cursor_pos().rx() += n_positions; + m_cursor_changed = true; +} + +void Screen::moveCursor(int x, int y) +{ + if (x != 0) + x--; + if (y != 0) + y--; + current_cursor_pos().setX(x); + int height = this->height(); + if (y >= height) { + current_cursor_pos().setY(height-1); + } else { + current_cursor_pos().setY(y); + } + m_cursor_changed = true; +} + +void Screen::moveCursorToLine(int line) +{ + current_cursor_pos().setY(line-1); + m_cursor_changed = true; +} + +void Screen::moveCursorToCharacter(int character) +{ + current_cursor_pos().setX(character-1); + m_cursor_changed = true; +} + +void Screen::deleteCharacters(int characters) +{ + switch (m_insert_mode) { + case Insert: + current_screen_data()->clearCharacters(current_cursor_y(), current_cursor_x(), current_cursor_x() + characters -1); + break; + case Replace: + current_screen_data()->deleteCharacters(current_cursor_y(), current_cursor_x(), current_cursor_x() + characters -1); + break; + default: + break; + } +} + +void Screen::setCursorVisible(bool visible) +{ + m_cursor_visible = visible; + m_cursor_visible_changed = true; +} + +bool Screen::cursorVisible() +{ + return m_cursor_visible; +} + +void Screen::setCursorBlinking(bool blinking) +{ + m_cursor_blinking = blinking; + m_cursor_blinking_changed = true; +} + +bool Screen::cursorBlinking() +{ + return m_cursor_blinking; +} + +void Screen::saveCursor() +{ + QPoint point = current_cursor_pos(); + m_cursor_stack << point; +} + +void Screen::restoreCursor() +{ + if (m_cursor_stack.size() <= 1) + return; + + m_cursor_stack.remove(m_screen_stack.size()-1); +} + +void Screen::replaceAtCursor(const QString &text) +{ + if (m_selection_valid ) { + if (current_cursor_y() >= m_selection_start.y() && current_cursor_y() <= m_selection_end.y()) + //don't need to schedule as event since it will only happen once + setSelectionEnabled(false); + } + + if (current_cursor_x() + text.size() <= width()) { + Line *line = current_screen_data()->at(current_cursor_y()); + line->replaceAtPos(current_cursor_x(), text, m_current_text_style); + current_cursor_pos().rx() += text.size(); + } else { + for (int i = 0; i < text.size();) { + if (current_cursor_x() == width()) { + current_cursor_pos().setX(0); + lineFeed(); + } + QString toLine = text.mid(i,current_screen_data()->width() - current_cursor_x()); + Line *line = current_screen_data()->at(current_cursor_y()); + line->replaceAtPos(current_cursor_x(),toLine, m_current_text_style); + i+= toLine.size(); + current_cursor_pos().rx() += toLine.size(); + } + } + + m_cursor_changed = true; +} + +void Screen::insertEmptyCharsAtCursor(int len) +{ + if (m_selection_valid) { + if (current_cursor_y() >= m_selection_start.y() && current_cursor_y() <= m_selection_end.y()) + //don't need to schedule as event since it will only happen once + setSelectionEnabled(false); + } + + Line *line = current_screen_data()->at(current_cursor_y()); + QString empty(len, QChar(' ')); + line->insertAtPos(current_cursor_x(), empty, defaultTextStyle()); +} + +void Screen::backspace() +{ + current_cursor_pos().rx()--; + m_cursor_changed = true; +} + +void Screen::eraseLine() +{ + current_screen_data()->clearLine(current_cursor_y()); +} + +void Screen::eraseFromCursorPositionToEndOfLine() +{ + current_screen_data()->clearToEndOfLine(current_cursor_y(), current_cursor_x()); +} + +void Screen::eraseFromCursorPosition(int n_chars) +{ + current_screen_data()->clearCharacters(current_cursor_y(), current_cursor_x(), current_cursor_x() + n_chars - 1); +} + +void Screen::eraseFromCurrentLineToEndOfScreen() +{ + current_screen_data()->clearToEndOfScreen(current_cursor_y()); +} + +void Screen::eraseFromCurrentLineToBeginningOfScreen() +{ + current_screen_data()->clearToBeginningOfScreen(current_cursor_y()); + +} + +void Screen::eraseToCursorPosition() +{ + qDebug() << "eraseToCursorPosition NOT IMPLEMENTED!"; +} + +void Screen::eraseScreen() +{ + current_screen_data()->clear(); +} + +void Screen::setTextStyleColor(ushort color) +{ + Q_ASSERT(color >= 30 && color < 50); + if (color < 38) { + m_current_text_style.forground = ColorPalette::Color(color - 30); + } else if (color == 39) { + m_current_text_style.forground = ColorPalette::DefaultForground; + } else if (color >= 40 && color < 48) { + m_current_text_style.background = ColorPalette::Color(color - 40); + } else if (color == 49) { + m_current_text_style.background = ColorPalette::DefaultBackground; + } else { + qDebug() << "Failed to set color"; + } +} + +const ColorPalette *Screen::colorPalette() const +{ + return &m_palette; +} + +void Screen::lineFeed() +{ + int cursor_y = current_cursor_y(); + if(cursor_y == current_screen_data()->scrollAreaEnd()) { + m_selection_start.ry()--; + m_selection_end.ry()--; + m_selection_moved = true; + moveLine(current_screen_data()->scrollAreaStart(),cursor_y); + } else { + current_cursor_pos().ry()++; + m_cursor_changed = true; + } +} + +void Screen::reverseLineFeed() +{ + int cursor_y = current_cursor_y(); + if (cursor_y == current_screen_data()->scrollAreaStart()) { + m_selection_start.ry()++; + m_selection_end.ry()++; + m_selection_moved = true; + moveLine(current_screen_data()->scrollAreaEnd(), cursor_y); + } else { + current_cursor_pos().ry()--; + m_cursor_changed = true; + } +} + +void Screen::insertLines(int count) +{ + for (int i = 0; i < count; i++) { + moveLine(current_screen_data()->scrollAreaEnd(),current_cursor_y()); + } +} + +void Screen::deleteLines(int count) +{ + for (int i = 0; i < count; i++) { + moveLine(current_cursor_y(),current_screen_data()->scrollAreaEnd()); + } + +} + +void Screen::setScrollArea(int from, int to) +{ + from--; + to--; + current_screen_data()->setScrollArea(from,to); +} + +QPointF Screen::selectionAreaStart() const +{ + return m_selection_start; +} + +void Screen::setSelectionAreaStart(const QPointF &start) +{ + bool emitChanged = m_selection_start != start; + m_selection_start = start; + setSelectionValidity(); + if (emitChanged) + emit selectionAreaStartChanged(); +} + +QPointF Screen::selectionAreaEnd() const +{ + return m_selection_end; +} + +void Screen::setSelectionAreaEnd(const QPointF &end) +{ + bool emitChanged = m_selection_end != end; + m_selection_end = end; + setSelectionValidity(); + if (emitChanged) + emit selectionAreaEndChanged(); +} + +bool Screen::selectionEnabled() const +{ + return m_selection_valid; +} + +void Screen::setSelectionEnabled(bool enabled) +{ + bool emitchanged = m_selection_valid != enabled; + m_selection_valid = enabled; + if (emitchanged) + emit selectionEnabledChanged(); +} + +void Screen::sendSelectionToClipboard() const +{ + current_screen_data()->sendSelectionToClipboard(m_selection_start, m_selection_end, QClipboard::Clipboard); +} + +void Screen::sendSelectionToSelection() const +{ + current_screen_data()->sendSelectionToClipboard(m_selection_start, m_selection_end, QClipboard::Selection); +} + +void Screen::pasteFromSelection() +{ + m_pty.write(QGuiApplication::clipboard()->text(QClipboard::Selection).toUtf8()); +} + +void Screen::pasteFromClipboard() +{ + m_pty.write(QGuiApplication::clipboard()->text(QClipboard::Clipboard).toUtf8()); +} + +void Screen::doubleClicked(const QPointF &clicked) +{ + int start, end; + current_screen_data()->getDoubleClickSelectionArea(clicked, &start, &end); + setSelectionAreaStart(QPointF(start,clicked.y())); + setSelectionAreaEnd(QPointF(end,clicked.y())); +} + +void Screen::setTitle(const QString &title) +{ + m_title = title; + emit screenTitleChanged(); +} + +QString Screen::title() const +{ + return m_title; +} + +void Screen::scheduleFlash() +{ + m_flash = true; +} + +Line *Screen::at(int i) const +{ + return current_screen_data()->at(i); +} + +void Screen::printScreen() const +{ + current_screen_data()->printStyleInformation(); +} + +void Screen::dispatchChanges() +{ + if (m_reset) { + emit reset(); + m_update_actions.clear(); + m_reset = false; + } else { + qint16 begin_move = -1; + qint16 end_move = -1; + for (int i = 0; i < m_update_actions.size(); i++) { + UpdateAction action = m_update_actions.at(i); + switch(action.action) { + case UpdateAction::MoveLine: { + if (begin_move < 0) { + begin_move = qMin(action.to_line, action.from_line); + end_move = qMax(action.to_line, action.from_line); + } else + if (action.from_line > action.to_line) { + begin_move = qMin(action.to_line, begin_move); + end_move = qMax(action.from_line, end_move); + } else { + begin_move = qMin(action.from_line, begin_move); + end_move = qMax(action.to_line, end_move); + } + } + break; + default: + qDebug() << "unhandeled UpdatAction in TerminalScreen"; + break; + } + } + + if (begin_move >= 0) { + current_screen_data()->updateIndexes(begin_move, end_move); + } + + current_screen_data()->dispatchLineEvents(); + emit dispatchTextSegmentChanges(); + } + + if (m_flash) { + m_flash = false; + emit flash(); + } + + if (m_cursor_changed) { + m_cursor_changed = false; + emit cursorPositionChanged(current_cursor_x(), current_cursor_y()); + } + + if (m_cursor_visible_changed) { + m_cursor_visible_changed = false; + emit cursorVisibleChanged(); + } + + if (m_cursor_blinking_changed) { + m_cursor_blinking_changed = false; + emit cursorBlinkingChanged(); + + } + + if (m_selection_valid && m_selection_moved) { + if (m_selection_start.y() < 0 || + m_selection_end.y() >= current_screen_data()->height()) { + setSelectionEnabled(false); + } else { + emit selectionAreaStartChanged(); + emit selectionAreaEndChanged(); + } + } + + m_update_actions.clear(); +} + +void Screen::sendPrimaryDA() +{ + m_pty.write(QByteArrayLiteral("\033[?6c")); + +} + +void Screen::sendSecondaryDA() +{ + m_pty.write(QByteArrayLiteral("\033[>1;95;0c")); +} + +void Screen::setCharacterMap(const QString &string) +{ + m_character_map = string; +} + +QString Screen::characterMap() const +{ + return m_character_map; +} + +void Screen::setApplicationCursorKeysMode(bool enable) +{ + m_application_cursor_key_mode = enable; +} + +bool Screen::applicationCursorKeyMode() const +{ + return m_application_cursor_key_mode; +} + +static bool hasControll(Qt::KeyboardModifiers modifiers) +{ +#ifdef Q_OS_MAC + return modifiers & Qt::MetaModifier; +#else + return modifiers & Qt::ControlModifier; +#endif +} + +static bool hasMeta(Qt::KeyboardModifiers modifiers) +{ +#ifdef Q_OS_MAC + return modifiers & Qt::ControlModifier; +#else + return modifiers & Qt::MetaModifier; +#endif +} + +void Screen::sendKey(const QString &text, Qt::Key key, Qt::KeyboardModifiers modifiers) +{ + /// UGH, this functions should be re-written + char escape = '\0'; + char control = '\0'; + char code = '\0'; + QVector parameters; + bool found = true; + + switch(key) { + case Qt::Key_Up: + escape = C0::ESC; + if (m_application_cursor_key_mode) + control = C1_7bit::SS3; + else + control = C1_7bit::CSI; + + code = 'A'; + break; + case Qt::Key_Right: + escape = C0::ESC; + if (m_application_cursor_key_mode) + control = C1_7bit::SS3; + else + control = C1_7bit::CSI; + + code = 'C'; + break; + case Qt::Key_Down: + escape = C0::ESC; + if (m_application_cursor_key_mode) + control = C1_7bit::SS3; + else + control = C1_7bit::CSI; + + code = 'B'; + break; + case Qt::Key_Left: + escape = C0::ESC; + if (m_application_cursor_key_mode) + control = C1_7bit::SS3; + else + control = C1_7bit::CSI; + + code = 'D'; + break; + case Qt::Key_Insert: + escape = C0::ESC; + control = C1_7bit::CSI; + parameters.append(2); + code = '~'; + break; + case Qt::Key_Delete: + escape = C0::ESC; + control = C1_7bit::CSI; + parameters.append(3); + code = '~'; + break; + case Qt::Key_Home: + escape = C0::ESC; + control = C1_7bit::CSI; + parameters.append(1); + code = '~'; + break; + case Qt::Key_End: + escape = C0::ESC; + control = C1_7bit::CSI; + parameters.append(4); + code = '~'; + break; + case Qt::Key_PageUp: + escape = C0::ESC; + control = C1_7bit::CSI; + parameters.append(5); + code = '~'; + break; + case Qt::Key_PageDown: + escape = C0::ESC; + control = C1_7bit::CSI; + parameters.append(6); + code = '~'; + break; + case Qt::Key_F1: + case Qt::Key_F2: + case Qt::Key_F3: + case Qt::Key_F4: + if (m_application_cursor_key_mode) { + parameters.append((key & 0xff) - 37); + escape = C0::ESC; + control = C1_7bit::CSI; + code = '~'; + } + break; + case Qt::Key_F5: + case Qt::Key_F6: + case Qt::Key_F7: + case Qt::Key_F8: + case Qt::Key_F9: + case Qt::Key_F10: + case Qt::Key_F11: + case Qt::Key_F12: + if (m_application_cursor_key_mode) { + parameters.append((key & 0xff) - 36); + escape = C0::ESC; + control = C1_7bit::CSI; + code = '~'; + } + break; + case Qt::Key_Control: + case Qt::Key_Shift: + case Qt::Key_Alt: + case Qt::Key_AltGr: + return; + break; + default: + found = false; + } + + if (found) { + int term_mods = 0; + if (modifiers & Qt::ShiftModifier) + term_mods |= 1; + if (modifiers & Qt::AltModifier) + term_mods |= 2; + if (modifiers & Qt::ControlModifier) + term_mods |= 4; + + QByteArray toPty; + + if (term_mods) { + term_mods++; + parameters.append(term_mods); + } + if (escape) + toPty.append(escape); + if (control) + toPty.append(control); + if (parameters.size()) { + for (int i = 0; i < parameters.size(); i++) { + if (i) + toPty.append(';'); + toPty.append(QByteArray::number(parameters.at(i))); + } + } + if (code) + toPty.append(code); + m_pty.write(toPty); + + } else { + QString verifiedText = text.simplified(); + if (verifiedText.isEmpty()) { + switch (key) { + case Qt::Key_Return: + case Qt::Key_Enter: + verifiedText = "\r"; + break; + case Qt::Key_Backspace: + verifiedText = "\010"; + break; + case Qt::Key_Tab: + verifiedText = "\t"; + break; + case Qt::Key_Control: + case Qt::Key_Meta: + case Qt::Key_Alt: + case Qt::Key_Shift: + return; + case Qt::Key_Space: + verifiedText = " "; + break; + default: + return; + } + } + QByteArray to_pty; + QByteArray key_text; + if (hasControll(modifiers)) { + char key_char = verifiedText.toLocal8Bit().at(0); + key_text.append(key_char & 0x1F); + } else { + key_text = verifiedText.toUtf8(); + } + + if (modifiers & Qt::AltModifier) { + to_pty.append(C0::ESC); + } + + if (hasMeta(modifiers)) { + to_pty.append(C0::ESC); + to_pty.append('@'); + to_pty.append(FinalBytesNoIntermediate::Reserved3); + } + + to_pty.append(key_text); + m_pty.write(to_pty); + } +} + +YatPty *Screen::pty() +{ + return &m_pty; +} + +Line *Screen::line_at_cursor() const +{ + return current_screen_data()->at(current_cursor_y()); +} + +void Screen::readData(const QByteArray &data) +{ + m_parser.addData(data); + + if (!m_timer_event_id) + m_timer_event_id = startTimer(3); + m_time_since_parsed.restart(); +} + +void Screen::moveLine(qint16 from, qint16 to) +{ + current_screen_data()->moveLine(from,to); + scheduleMoveSignal(from,to); +} + +void Screen::scheduleMoveSignal(qint16 from, qint16 to) +{ + if (m_update_actions.size() && + m_update_actions.last().action == UpdateAction::MoveLine && + m_update_actions.last().from_line == from && + m_update_actions.last().to_line == to) { + m_update_actions.last().count++; + } else { + m_update_actions << UpdateAction(UpdateAction::MoveLine, from, to, 1); + } +} + + +void Screen::setSelectionValidity() +{ + if (m_selection_end.y() > m_selection_start.y() || + (m_selection_end.y() == m_selection_start.y() && + m_selection_end.x() > m_selection_start.x())) { + setSelectionEnabled(true); + } else { + setSelectionEnabled(false); + } +} + + +void Screen::timerEvent(QTimerEvent *) +{ + if (m_timer_event_id && m_time_since_parsed.elapsed() > 3) { + killTimer(m_timer_event_id); + m_timer_event_id = 0; + dispatchChanges(); + } +} diff --git a/yat/backend/screen.h b/yat/backend/screen.h new file mode 100644 index 0000000..b665a19 --- /dev/null +++ b/yat/backend/screen.h @@ -0,0 +1,243 @@ +/************************************************************************************************** +* Copyright (c) 2012 Jørgen Lind +* +* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +* associated documentation files (the "Software"), to deal in the Software without restriction, +* including without limitation the rights to use, copy, modify, merge, publish, distribute, +* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all copies or +* substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT +* NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +* OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +***************************************************************************************************/ + +#ifndef TERMINALSCREEN_H +#define TERMINALSCREEN_H + +#include + +#include "text.h" +#include "color_palette.h" +#include "parser.h" +#include "yat_pty.h" +#include "update_action.h" +#include "screen_data.h" + +#include +#include +#include +#include + +class Line; +class QQuickItem; +class QQmlEngine; +class QQmlComponent; + +class Screen : public QObject +{ + Q_OBJECT + + Q_PROPERTY(int height READ height WRITE setHeight) + Q_PROPERTY(int width READ width WRITE setWidth) + Q_PROPERTY(QString title READ title WRITE setTitle NOTIFY screenTitleChanged) + Q_PROPERTY(bool cursorVisible READ cursorVisible NOTIFY cursorVisibleChanged) + Q_PROPERTY(bool cursorBlinking READ cursorBlinking NOTIFY cursorBlinkingChanged) + Q_PROPERTY(bool selectionEnabled READ selectionEnabled NOTIFY selectionEnabledChanged) + Q_PROPERTY(QPointF selectionAreaStart READ selectionAreaStart WRITE setSelectionAreaStart NOTIFY selectionAreaStartChanged) + Q_PROPERTY(QPointF selectionAreaEnd READ selectionAreaEnd WRITE setSelectionAreaEnd NOTIFY selectionAreaEndChanged) + +public: + enum InsertMode { + Insert, + Replace + }; + + explicit Screen(QObject *parent = 0); + ~Screen(); + + void setHeight(int height); + int height() const; + void setWidth(int width); + int width() const; + + void saveScreenData(); + void restoreScreenData(); + + void setInsertMode(InsertMode mode); + + void setTextStyle(TextStyle::Style style, bool add = true); + void resetStyle(); + TextStyle currentTextStyle() const; + TextStyle defaultTextStyle() const; + + Q_INVOKABLE QColor screenBackground(); + QColor defaultForgroundColor() const; + QColor defaultBackgroundColor() const; + + void setTextStyleColor(ushort color); + const ColorPalette *colorPalette() const; + + QPoint cursorPosition() const; + + void moveCursorHome(); + void moveCursorTop(); + void moveCursorUp(int n_positions = 1); + void moveCursorDown(); + void moveCursorLeft(); + void moveCursorRight(int n_positions); + void moveCursor(int x, int y); + void moveCursorToLine(int line); + void moveCursorToCharacter(int character); + + void deleteCharacters(int characters); + + void setCursorVisible(bool visible); + bool cursorVisible(); + void setCursorBlinking(bool blinking); + bool cursorBlinking(); + void saveCursor(); + void restoreCursor(); + + void replaceAtCursor(const QString &text); + + void insertEmptyCharsAtCursor(int len); + + void backspace(); + + void eraseLine(); + void eraseFromCursorPositionToEndOfLine(); + void eraseFromCursorPosition(int n_chars); + void eraseFromCurrentLineToEndOfScreen(); + void eraseFromCurrentLineToBeginningOfScreen(); + void eraseToCursorPosition(); + void eraseScreen(); + + void lineFeed(); + void reverseLineFeed(); + void insertLines(int count); + void deleteLines(int count); + + void setScrollArea(int from, int to); + + QPointF selectionAreaStart() const; + void setSelectionAreaStart(const QPointF &start); + QPointF selectionAreaEnd() const; + void setSelectionAreaEnd(const QPointF &end); + + bool selectionEnabled() const; + Q_INVOKABLE void setSelectionEnabled(bool enabled); + + Q_INVOKABLE void sendSelectionToClipboard() const; + Q_INVOKABLE void sendSelectionToSelection() const; + Q_INVOKABLE void pasteFromSelection(); + Q_INVOKABLE void pasteFromClipboard(); + + Q_INVOKABLE void doubleClicked(const QPointF &clicked); + + void setTitle(const QString &title); + QString title() const; + + void scheduleFlash(); + + Q_INVOKABLE Line *at(int i) const; + + Q_INVOKABLE void printScreen() const; + + void dispatchChanges(); + + void sendPrimaryDA(); + void sendSecondaryDA(); + + void setCharacterMap(const QString &string); + QString characterMap() const; + void setApplicationCursorKeysMode(bool enable); + bool applicationCursorKeyMode() const; + + Q_INVOKABLE void sendKey(const QString &text, Qt::Key key, Qt::KeyboardModifiers modifiers); + + YatPty *pty(); + + //For tests + Line *line_at_cursor() const; +public slots: + void readData(const QByteArray &data); + +signals: + void moveLines(int from_line, int to_line, int count); + + void reset(); + + void flash(); + + void dispatchLineChanges(); + void dispatchTextSegmentChanges(); + + void selectionAreaStartChanged(); + void selectionAreaEndChanged(); + void selectionEnabledChanged(); + + void screenTitleChanged(); + + void cursorPositionChanged(int x, int y); + void cursorVisibleChanged(); + void cursorBlinkingChanged(); + + void lineCreated(Line *line); +protected: + void timerEvent(QTimerEvent *); + +private: + void moveLine(qint16 from, qint16 to); + void scheduleMoveSignal(qint16 from, qint16 to); + + ScreenData *current_screen_data() const { return m_screen_stack[m_screen_stack.size()-1]; } + QPoint ¤t_cursor_pos() { return m_cursor_stack[m_cursor_stack.size()-1]; } + int current_cursor_x() const { return m_cursor_stack.at(m_cursor_stack.size()-1).x(); } + int current_cursor_y() const { return m_cursor_stack.at(m_cursor_stack.size()-1).y(); } + + void setSelectionValidity(); + + ColorPalette m_palette; + YatPty m_pty; + Parser m_parser; + QElapsedTimer m_time_since_parsed; + + int m_timer_event_id; + + QVector m_screen_stack; + QVector m_cursor_stack; + + bool m_cursor_visible; + bool m_cursor_visible_changed; + bool m_cursor_blinking; + bool m_cursor_blinking_changed; + + TextStyle m_current_text_style; + QString m_title; + + InsertMode m_insert_mode; + + bool m_selection_valid; + bool m_selection_moved; + QPointF m_selection_start; + QPointF m_selection_end; + + QString m_character_map; + + QList m_update_actions; + bool m_flash; + bool m_cursor_changed; + bool m_reset; + bool m_application_cursor_key_mode; + + friend class ScreenData; +}; + +#endif // TERMINALSCREEN_H diff --git a/yat/backend/screen_data.cpp b/yat/backend/screen_data.cpp new file mode 100644 index 0000000..64a58ac --- /dev/null +++ b/yat/backend/screen_data.cpp @@ -0,0 +1,317 @@ +/************************************************************************************************** +* Copyright (c) 2012 Jørgen Lind +* +* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +* associated documentation files (the "Software"), to deal in the Software without restriction, +* including without limitation the rights to use, copy, modify, merge, publish, distribute, +* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all copies or +* substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT +* NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +* OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +***************************************************************************************************/ + +#include "screen_data.h" + +#include "line.h" +#include "screen.h" + +#include + +#include +#include + +ScreenData::ScreenData(Screen *screen) + : m_screen(screen) + , m_scroll_start(0) + , m_scroll_end(0) + , m_scroll_area_set(false) +{ +} + +ScreenData::~ScreenData() +{ + for (int i = 0; i < m_screen_lines.size(); i++) { + delete m_screen_lines.at(i); + } +} + + +int ScreenData::width() const +{ + return m_width; +} + +void ScreenData::setWidth(int width) +{ + if (width == m_width) + return; + + m_width = width; + + for (int i = 0; i < m_screen_lines.size(); i++) { + m_screen_lines.at(i)->setWidth(width); + } +} + +int ScreenData::height() const +{ + return m_screen_lines.size(); +} + +void ScreenData::setHeight(int height) +{ + if (height == m_screen_lines.size()) + return; + + if (m_screen_lines.size() > height) { + int removeElements = m_screen_lines.size() - height; + for (int i = 0; i < m_screen_lines.size(); i++) { + if (i = 0) + m_new_lines.remove(not_broadcasted); + delete m_screen_lines[i]; + } else { + m_screen_lines.at(i)->setIndex(i - removeElements); + } + } + m_screen_lines.remove(0, removeElements); + } else if (m_screen_lines.size() < height){ + int rowsToAdd = height - m_screen_lines.size(); + for (int i = 0; i < rowsToAdd; i++) { + Line *newLine = new Line(m_screen); + m_screen_lines.append(newLine); + m_new_lines.append(newLine); + newLine->setIndex(m_screen_lines.size()-1); + } + } + if (!m_scroll_area_set) + m_scroll_end = height - 1; +} + +int ScreenData::scrollAreaStart() const +{ + return m_scroll_start; +} + +int ScreenData::scrollAreaEnd() const +{ + return m_scroll_end; +} + +Line *ScreenData::at(int index) const +{ + return m_screen_lines.at(index); +} + +void ScreenData::clearToEndOfLine(int row, int from_char) +{ + m_screen_lines.at(row)->clearToEndOfLine(from_char); +} + +void ScreenData::clearToEndOfScreen(int row) +{ + for(int i = row; i < m_screen_lines.size(); i++) { + Line *line = m_screen_lines.at(i); + line->clear(); + } +} + +void ScreenData::clearToBeginningOfScreen(int row) +{ + for (int i = row; i >= 0; i--) { + Line *line = m_screen_lines.at(i); + line->clear(); + } +} + +void ScreenData::clearLine(int index) +{ + m_screen_lines.at(index)->clear(); +} + +void ScreenData::clear() +{ + for (int i = 0; i < m_screen_lines.size(); i++) { + Line *line = m_screen_lines.at(i); + line->clear(); + } +} + +void ScreenData::clearCharacters(int line, int from, int to) +{ + Line *line_item = m_screen_lines.at(line); + line_item->clearCharacters(from,to); +} + +void ScreenData::deleteCharacters(int line, int from, int to) +{ + Line *line_item = m_screen_lines.at(line); + line_item->deleteCharacters(from,to); +} + +void ScreenData::setScrollArea(int from, int to) +{ + m_scroll_area_set = true; + m_scroll_start = from; + m_scroll_end = to; +} + +void ScreenData::moveLine(int from, int to) +{ + if (from == to) + return; + + if (from < to) { + int lines_to_shift = to - from; + Line *from_line = m_screen_lines.at(from); + Line **from_line_ptr = m_screen_lines.data() + from; + memmove(from_line_ptr, from_line_ptr+1, sizeof(from_line_ptr) * lines_to_shift); + from_line->clear(); + m_screen_lines.replace(to,from_line); + } else { + int lines_to_shift = from - to; + Line *from_line = m_screen_lines.at(from); + Line **to_line_ptr = const_cast(m_screen_lines.constData() + to); + memmove(to_line_ptr + 1, to_line_ptr, sizeof(to_line_ptr) * lines_to_shift); + from_line->clear(); + m_screen_lines.replace(to,from_line); + } +} + +void ScreenData::updateIndexes(int from, int to) +{ + if (to < 0) { + to = m_screen_lines.size() -1; + } + for (int i = from; i <= to; i++) { + m_screen_lines.at(i)->setIndex(i); + } +} + +void ScreenData::sendSelectionToClipboard(const QPointF &start, const QPointF &end, QClipboard::Mode clipboard) +{ + QString data; + int start_line = qMax((int)start.y(), 0); + int end_line = qMin((int)end.y(), m_screen_lines.size()-1); + for (int i = start_line; i <= end_line; i++) { + int char_start = 0; + int char_end = m_width - 1; + if (i == start_line) + char_start = start.x(); + else + data.append(QChar('\n')); + if (i == end_line) + char_end = end.x(); + data += m_screen_lines.at(i)->textLine()->mid(char_start, char_end - char_start).trimmed(); + } + + QGuiApplication::clipboard()->setText(data, clipboard); +} + +void ScreenData::getDoubleClickSelectionArea(const QPointF &cliked, int *start_ret, int *end_ret) const +{ + static const QChar delimiter_list[] = { + ' ', + '<', + '>', + ')', + '(', + '{', + '}', + '[', + ']' + }; + static const int size_of_delimiter_list = sizeof delimiter_list / sizeof *delimiter_list; + + *start_ret = -1; + *end_ret = -1; + bool find_equals = false; + + QStringRef to_return(m_screen_lines.at(cliked.y())->textLine()); + + QChar clicked_char = to_return.at(cliked.x()); + + for (int i=0; i= 0; i--) { + if (find_equals) { + if (clicked_char != to_return.at(i)) { + *start_ret = i + 1; + break; + } + } else { + for (int delimiter_i = 0; delimiter_i < size_of_delimiter_list; delimiter_i++) { + if (to_return.at(i) == delimiter_list[delimiter_i]) { + *start_ret = i + 1; + i = -1; + break; + } + } + } + } + if (*start_ret < 0) + *start_ret = 0; + + for (int i = cliked.x() + 1; i < to_return.size(); i++) { + if (find_equals) { + if (clicked_char != to_return.at(i)) { + *end_ret = i; + break; + } + } else { + for (int delimiter_i = 0; delimiter_i < size_of_delimiter_list; delimiter_i++) { + if (to_return.at(i) == delimiter_list[delimiter_i]) { + *end_ret = i; + i = to_return.size(); + break; + } + } + } + } + if (*end_ret < 0) + *end_ret = to_return.size(); + +} + +void ScreenData::dispatchLineEvents() +{ + for (int i = 0; i < m_new_lines.size(); i++) { + emit m_screen->lineCreated(m_new_lines.at(i)); + } + m_new_lines.clear(); + + for (int i = 0; i < m_screen_lines.size(); i++) { + m_screen_lines.at(i)->dispatchEvents(); + } +} + +void ScreenData::printScreen() const +{ + for (int line = 0; line < m_screen_lines.size(); line++) { +// for (int i = 0; i < m_screen_lines.at(line)->size(); i++) { +// fprintf(stderr, "%s", qPrintable(m_screen_lines.at(line)->at(i)->text())); +// } +// fprintf(stderr, "\n"); + fprintf(stderr, "%s\n", qPrintable(*m_screen_lines.at(line)->textLine())); + } +} + +void ScreenData::printStyleInformation() const +{ + for (int line_number = 0; line_number < m_screen_lines.size(); line_number++) { + const Line *line = m_screen_lines.at(line_number); + line->printStyleList(); + } +} diff --git a/yat/backend/screen_data.h b/yat/backend/screen_data.h new file mode 100644 index 0000000..858d339 --- /dev/null +++ b/yat/backend/screen_data.h @@ -0,0 +1,81 @@ +/************************************************************************************************** +* Copyright (c) 2012 Jørgen Lind +* +* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +* associated documentation files (the "Software"), to deal in the Software without restriction, +* including without limitation the rights to use, copy, modify, merge, publish, distribute, +* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all copies or +* substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT +* NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +* OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +***************************************************************************************************/ + +#ifndef SCREENDATA_H +#define SCREENDATA_H + +#include +#include +#include + +class Line; +class Screen; + +class ScreenData +{ +public: + ScreenData(Screen *screen); + ~ScreenData(); + + int width() const; + void setWidth(int width); + int height() const; + void setHeight(int height); + + int scrollAreaStart() const; + int scrollAreaEnd() const; + + Line *at(int index) const; + + void clearToEndOfLine(int row, int from_char); + void clearToEndOfScreen(int row); + void clearToBeginningOfScreen(int row); + void clearLine(int index); + void clear(); + + void clearCharacters(int line, int from, int to); + void deleteCharacters(int line, int from, int to); + + void setScrollArea(int from, int to); + + void moveLine(int from, int to); + + void updateIndexes(int from = 0, int to = -1); + + void sendSelectionToClipboard(const QPointF &start, const QPointF &end, QClipboard::Mode clipboard); + + void getDoubleClickSelectionArea(const QPointF &cliked, int *start_ret, int *end_ret) const; + + void dispatchLineEvents(); + + void printScreen() const; + + void printStyleInformation() const; +private: + Screen *m_screen; + int m_width; + QVector m_screen_lines; + QVector m_new_lines; + int m_scroll_start; + int m_scroll_end; + bool m_scroll_area_set; +}; + +#endif // SCREENDATA_H diff --git a/yat/backend/text.cpp b/yat/backend/text.cpp new file mode 100644 index 0000000..c084623 --- /dev/null +++ b/yat/backend/text.cpp @@ -0,0 +1,147 @@ +/************************************************************************************************** +* Copyright (c) 2012 Jørgen Lind +* +* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +* associated documentation files (the "Software"), to deal in the Software without restriction, +* including without limitation the rights to use, copy, modify, merge, publish, distribute, +* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all copies or +* substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT +* NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +* OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +***************************************************************************************************/ + +#include "text.h" + +#include "screen.h" +#include "line.h" +#include + +#include + +Text::Text(Screen *screen) + : QObject(screen) + , m_style_dirty(true) + , m_text_dirty(true) + , m_visible(true) + , m_visible_old(true) + , m_line(0) +{ +} + +Text::~Text() +{ + emit aboutToBeDestroyed(); +} + +void Text::setLine(Line *line) +{ + if (line == m_line) + return; + m_line = line; + if (m_line) { + m_text_line = line->textLine(); + } +} + +int Text::index() const +{ + return m_start_index; +} + +bool Text::visible() const +{ + return m_visible; +} + +void Text::setVisible(bool visible) +{ + m_visible = visible; +} + +QString Text::text() const +{ + return m_text; +} + +QColor Text::foregroundColor() const +{ + if (m_style.style & TextStyle::Inverse) { + if (m_style.background == ColorPalette::DefaultBackground) + return screen()->screenBackground(); + return screen()->colorPalette()->color(m_style.background, m_style.style & TextStyle::Bold); + } + + return screen()->colorPalette()->color(m_style.forground, m_style.style & TextStyle::Bold); +} + + +QColor Text::backgroundColor() const +{ + if (m_style.style & TextStyle::Inverse) + return screen()->colorPalette()->color(m_style.forground, false); + + return screen()->colorPalette()->color(m_style.background, false); +} + +void Text::setStringSegment(int start_index, int end_index, bool text_changed) +{ + m_start_index = start_index; + m_end_index = end_index; + + m_text_dirty = text_changed; +} + +void Text::setTextStyle(const TextStyle &style) +{ + m_new_style = style; + m_style_dirty = true; +} + +Screen *Text::screen() const +{ + return m_line->screen(); +} + +void Text::dispatchEvents() +{ + if (m_style_dirty) { + m_style_dirty = false; + + bool emit_forground = m_new_style.forground != m_style.forground; + bool emit_background = m_new_style.background != m_style.background; + bool emit_text_style = m_new_style.style != m_style.style; + + m_style = m_new_style; + if (emit_forground) + emit forgroundColorChanged(); + if (emit_background) + emit backgroundColorChanged(); + if (emit_text_style) + emit textStyleChanged(); + } + + if (m_old_start_index != m_start_index + || m_text_dirty) { + m_text_dirty = false; + m_text = m_text_line->mid(m_start_index, m_end_index + 1 - m_start_index); + if (m_old_start_index != m_start_index) { + m_old_start_index = m_start_index; + emit indexChanged(); + } + emit textChanged(); + } + + if (m_visible_old != m_visible) { + m_visible_old = m_visible; + emit visibleChanged(); + } +} + diff --git a/yat/backend/text.h b/yat/backend/text.h new file mode 100644 index 0000000..165de5b --- /dev/null +++ b/yat/backend/text.h @@ -0,0 +1,96 @@ +/************************************************************************************************** +* Copyright (c) 2012 Jørgen Lind +* +* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +* associated documentation files (the "Software"), to deal in the Software without restriction, +* including without limitation the rights to use, copy, modify, merge, publish, distribute, +* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all copies or +* substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT +* NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +* OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +***************************************************************************************************/ + +#ifndef TEXT_SEGMENT_H +#define TEXT_SEGMENT_H + +#include +#include +#include +#include + +#include "text_style.h" + +class Screen; +class Line; +class QQuickItem; + +class Text : public QObject +{ + Q_OBJECT + Q_PROPERTY(int index READ index NOTIFY indexChanged) + Q_PROPERTY(bool visible READ visible NOTIFY visibleChanged) + Q_PROPERTY(QString text READ text NOTIFY textChanged) + Q_PROPERTY(QColor foregroundColor READ foregroundColor NOTIFY forgroundColorChanged) + Q_PROPERTY(QColor backgroundColor READ backgroundColor NOTIFY backgroundColorChanged) + Q_PROPERTY(Screen *screen READ screen CONSTANT) +public: + Text(Screen *screen); + ~Text(); + + void setLine(Line *line); + + int index() const; + + bool visible() const; + void setVisible(bool visible); + + QString text() const; + QColor foregroundColor() const; + QColor backgroundColor() const; + + void setStringSegment(int start_index, int end_index, bool textChanged); + void setTextStyle(const TextStyle &style); + + Screen *screen() const; + + QObject *item() const; + +public slots: + void dispatchEvents(); + +signals: + void indexChanged(); + void visibleChanged(); + void textChanged(); + void forgroundColorChanged(); + void backgroundColorChanged(); + void textStyleChanged(); + + void aboutToBeDestroyed(); +private: + + QString m_text; + QString *m_text_line; + int m_start_index; + int m_old_start_index; + int m_end_index; + TextStyle m_style; + TextStyle m_new_style; + + bool m_style_dirty; + bool m_text_dirty; + bool m_visible; + bool m_visible_old; + + Line *m_line; +}; + +#endif // TEXT_SEGMENT_H diff --git a/yat/backend/text_style.cpp b/yat/backend/text_style.cpp new file mode 100644 index 0000000..6d8d220 --- /dev/null +++ b/yat/backend/text_style.cpp @@ -0,0 +1,17 @@ +#include "text_style.h" + +#include + +TextStyle::TextStyle() + : style(Normal) + , forground(ColorPalette::DefaultForground) + , background(ColorPalette::DefaultBackground) +{ + +} +bool TextStyle::isCompatible(const TextStyle &other) const +{ + return forground == other.forground + && background == other.background + && style == other.style; +} diff --git a/yat/backend/text_style.h b/yat/backend/text_style.h new file mode 100644 index 0000000..f87b660 --- /dev/null +++ b/yat/backend/text_style.h @@ -0,0 +1,37 @@ +#ifndef TEXT_STYLE_H +#define TEXT_STYLE_H + +#include + +#include "color_palette.h" +class Screen; + +class TextStyle +{ +public: + enum Style { + Normal = 0x0000, + Italic = 0x0001, + Bold = 0x0002, + Underlined = 0x0004, + Blinking = 0x0008, + FastBlinking = 0x0010, + Gothic = 0x0020, + DoubleUnderlined = 0x0040, + Framed = 0x0080, + Overlined = 0x0100, + Encircled = 0x0200, + Inverse = 0x0400 + }; + Q_DECLARE_FLAGS(Styles, Style) + + TextStyle(); + + Styles style; + ColorPalette::Color forground; + ColorPalette::Color background; + + bool isCompatible(const TextStyle &other) const; +}; + +#endif // TEXT_STYLE_H diff --git a/yat/backend/update_action.cpp b/yat/backend/update_action.cpp new file mode 100644 index 0000000..8bfb568 --- /dev/null +++ b/yat/backend/update_action.cpp @@ -0,0 +1,21 @@ +/************************************************************************************************** +* Copyright (c) 2012 Jørgen Lind +* +* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +* associated documentation files (the "Software"), to deal in the Software without restriction, +* including without limitation the rights to use, copy, modify, merge, publish, distribute, +* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all copies or +* substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT +* NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +* OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +***************************************************************************************************/ + +#include "update_action.h" diff --git a/yat/backend/update_action.h b/yat/backend/update_action.h new file mode 100644 index 0000000..6d71a28 --- /dev/null +++ b/yat/backend/update_action.h @@ -0,0 +1,54 @@ +/************************************************************************************************** +* Copyright (c) 2012 Jørgen Lind +* +* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +* associated documentation files (the "Software"), to deal in the Software without restriction, +* including without limitation the rights to use, copy, modify, merge, publish, distribute, +* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all copies or +* substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT +* NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +* OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +***************************************************************************************************/ + +#ifndef UPDATE_ACTION_H +#define UPDATE_ACTION_H + +#include + +class UpdateAction +{ +public: + enum Action { + InvalidAction, + MoveLine + }; + + UpdateAction(Action action, qint16 from_line, qint16 to_line, qint16 count) + : action(action) + , from_line(from_line) + , to_line(to_line) + , count(count) + { } + + UpdateAction(Action action, int count) + : action(action) + , from_line(0) + , to_line(0) + , count(count) + { } + + Action action; + qint16 from_line; + qint16 to_line; + qint16 count; +}; + +#endif // UPDATE_ACTION_H diff --git a/yat/backend/yat_pty.cpp b/yat/backend/yat_pty.cpp new file mode 100644 index 0000000..ae83cfd --- /dev/null +++ b/yat/backend/yat_pty.cpp @@ -0,0 +1,139 @@ +/************************************************************************************************** +* Copyright (c) 2012 Jørgen Lind +* +* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +* associated documentation files (the "Software"), to deal in the Software without restriction, +* including without limitation the rights to use, copy, modify, merge, publish, distribute, +* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all copies or +* substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT +* NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +* OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +***************************************************************************************************/ + +#include "yat_pty.h" + +#include +#include + +#ifdef LINUX +#include +#endif + +#include +#ifdef Q_OS_MAC +#include +#else +#include +#endif +#include + +#include +#include +#include +#include +#include + +static char env_variables[][255] = { + "TERM=xterm", + "COLORTERM=xterm", + "COLORFGBG=15;0", + "LINES", + "COLUMNS", + "TERMCAP" +}; +static int env_variables_size = sizeof(env_variables) / sizeof(env_variables[0]); + +YatPty::YatPty() + : m_winsize(0) +{ + m_terminal_pid = forkpty(&m_master_fd, + NULL, + NULL, + NULL); + + if (m_terminal_pid == 0) { + for (int i = 0; i < env_variables_size; i++) { + ::putenv(env_variables[i]); + } + ::execl("/bin/bash", "/bin/bash", "--login", (const char *) 0); + exit(0); + } + + QSocketNotifier *reader = new QSocketNotifier(m_master_fd,QSocketNotifier::Read,this); + connect(reader, &QSocketNotifier::activated, this, &YatPty::readData); +} + +YatPty::~YatPty() +{ +} + +void YatPty::write(const QByteArray &data) +{ + if (::write(m_master_fd, data.constData(), data.size()) < 0) { + qDebug() << "Something whent wrong when writing to m_master_fd"; + } +} + +void YatPty::setWidth(int width, int pixelWidth) +{ + if (!m_winsize) { + m_winsize = new struct winsize; + m_winsize->ws_row = 25; + m_winsize->ws_ypixel = 0; + } + + m_winsize->ws_col = width; + m_winsize->ws_xpixel = pixelWidth; + ioctl(m_master_fd, TIOCSWINSZ, m_winsize); +} + +void YatPty::setHeight(int height, int pixelHeight) +{ + if (!m_winsize) { + m_winsize = new struct winsize; + m_winsize->ws_col = 80; + m_winsize->ws_xpixel = 0; + } + m_winsize->ws_row = height; + m_winsize->ws_ypixel = pixelHeight; + ioctl(m_master_fd, TIOCSWINSZ, m_winsize); + +} + +QSize YatPty::size() const +{ + if (!m_winsize) { + YatPty *that = const_cast(this); + that->m_winsize = new struct winsize; + ioctl(m_master_fd, TIOCGWINSZ, m_winsize); + } + return QSize(m_winsize->ws_col, m_winsize->ws_row); +} + +int YatPty::masterDevice() const +{ + return m_master_fd; +} + + +void YatPty::readData() +{ + int size_of_buffer = sizeof m_data_buffer / sizeof *m_data_buffer; + ssize_t read_size = ::read(m_master_fd,m_data_buffer,size_of_buffer); + if (read_size > 0) { + QByteArray to_return = QByteArray::fromRawData(m_data_buffer,read_size); + emit readyRead(to_return); + } else if (read_size < 0) { + emit hangupReceived(); + } else { + emit hangupReceived(); + } +} diff --git a/yat/backend/yat_pty.h b/yat/backend/yat_pty.h new file mode 100644 index 0000000..64c7a2c --- /dev/null +++ b/yat/backend/yat_pty.h @@ -0,0 +1,59 @@ +/************************************************************************************************** +* Copyright (c) 2012 Jørgen Lind +* +* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +* associated documentation files (the "Software"), to deal in the Software without restriction, +* including without limitation the rights to use, copy, modify, merge, publish, distribute, +* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all copies or +* substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT +* NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +* OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +***************************************************************************************************/ + +#ifndef YAT_PTY_H +#define YAT_PTY_H + +#include + +#include +#include +#include + +class YatPty : public QObject +{ + Q_OBJECT +public: + YatPty(); + ~YatPty(); + + void write(const QByteArray &data); + + void setWidth(int width, int pixelWidth = 0); + void setHeight(int height, int pixelHeight = 0); + QSize size() const; + + int masterDevice() const; + +signals: + void hangupReceived(); + void readyRead(const QByteArray &data); + +private: + void readData(); + + pid_t m_terminal_pid; + int m_master_fd; + char m_slave_file_name[PATH_MAX]; + struct winsize *m_winsize; + char m_data_buffer[4096]; +}; + +#endif //YAT_PTY_H diff --git a/yat/docs/Ecma-048.pdf b/yat/docs/Ecma-048.pdf new file mode 100644 index 0000000..e1441c5 Binary files /dev/null and b/yat/docs/Ecma-048.pdf differ diff --git a/yat/docs/Xterm Control Sequences.html b/yat/docs/Xterm Control Sequences.html new file mode 100644 index 0000000..cf3453c --- /dev/null +++ b/yat/docs/Xterm Control Sequences.html @@ -0,0 +1,4841 @@ + + + + + + + + + +Xterm Control Sequences + + + + +

Xterm Control Sequences

+ +Definitions
+C1 (8-Bit) Control Characters
+VT100 Mode
+Alt and Meta Keys
+PC-Style Function Keys
+VT220-Style Function Keys
+VT52-Style Function Keys
+Sun-Style Function Keys
+HP-Style Function Keys
+The Alternate Screen Buffer
+Bracketed Paste Mode
+Title Modes
+Mouse Tracking
+Tektronix 4014 Mode
+VT52 Mode
+ +
+ + +

Edward Moy
+University of California, Berkeley

+ + +

Revised +by
+Stephen Gildea

+X Consortium (1994)
+Thomas Dickey

+XFree86 Project (1996-2006)
+invisible-island.net (2006-2012)

+ + +

Definitions

+ + + + + + + + + + + + + + + + + + + + + + + +
+ + +

c

+ + +

The literal +character c.

+ + +

C

+ + +

A single (required) +character.

+ + +

P +s

+ + +

A single (usually +optional) numeric parameter, composed of one of more +digits.

+ + +

P +m

+ + +

A multiple numeric +parameter composed of any number of single numeric +parameters, separated by ; character(s). Individual values +for the parameters are listed with P s +.

+ + +

P +t

+ + +

A text parameter +composed of printable characters.

+ + +

C1 (8-Bit) Control Characters

+ + +

The xterm +program recognizes both 8-bit and 7-bit control characters. +It generates 7-bit controls (by default) or 8-bit if S8C1T +is enabled. The following pairs of 7-bit and 8-bit control +characters are equivalent:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +

ESC +D

+ + +

Index ( +IND is 0x84).

+ + +

ESC E

+ + +

Next Line ( +NEL is 0x85).

+ + +

ESC H

+ + +

Tab Set ( HTS +is 0x88).

+ + +

ESC M

+ + +

Reverse Index ( +RI is 0x8d).

+ + +

ESC N

+ + +

Single Shift Select of G2 Character Set ( +SS2 is 0x8e). This affects +next character only.

+ + +

ESC O

+ + +

Single Shift Select of G3 Character Set ( +SS3 is 0x8f). This affects +next character only.

+ + +

ESC P

+ + +

Device Control String ( +DCS is 0x90).

+ + +

ESC V

+ + +

Start of Guarded Area ( +SPA is 0x96).

+ + +

ESC W

+ + +

End of Guarded Area ( +EPA is 0x97).

+ + +

ESC X

+ + +

Start of String ( +SOS is 0x98).

+ + +

ESC Z

+ + +

Return Terminal ID (DECID is 0x9a). +Obsolete form of CSI c +(DA).

+ + +

ESC [

+ + +

Control Sequence Introducer ( +CSI is 0x9b).

+ + +

ESC \

+ + +

String Terminator ( +ST is 0x9c).

+ + +

ESC ]

+ + +

Operating System Command ( +OSC is 0x9d).

+ + +

ESC ^

+ + +

Privacy Message ( +PM is 0x9e).

+ + +

ESC _

+ + +

Application Program Command ( +APC is 0x9f).

+ +

These control +characters are used in the vtXXX emulation.

+ + +

VT100 Mode

+ + +

Most of these +control sequences are standard VT102 control sequences, but +there is support for later DEC VT terminals (i.e., VT220, +VT320, VT420, VT510), as well as ISO 6429 and aixterm +color controls. The only VT102 feature not supported is +auto-repeat, since the only way X provides for this will +affect all windows. There are additional control sequences +to provide xterm-dependent functions, such as the +scrollbar or window size. Where the function is specified by +DEC or ISO 6429, the code assigned to it is given in +parentheses. The escape codes to designate and invoke +character sets are specified by ISO 2022; see that document +for a discussion of character sets.

+ + +

Single-character +functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +

BEL

+ + +

Bell (Ctrl-G).

+ + +

BS

+ + +

Backspace (Ctrl-H).

+ + +

CR

+ + +

Carriage Return (Ctrl-M).

+ + +

ENQ

+ + +

Return Terminal Status (Ctrl-E). Default +response is an empty string, but may be overridden by a +resource answerbackString.

+ + +

FF

+ + +

Form Feed or New Page (NP). Ctrl-L is +treated the same as LF.

+ + +

LF

+ + +

Line Feed or New Line (NL). (LF is +Ctrl-J).

+ + +

SI

+ + +

Shift In (Ctrl-O) → Switch to Standard +Character Set. This invokes the G0 character set (the +default).

+ + +

SO

+ + +

Shift Out (Ctrl-N) → Switch to +Alternate Character Set. This invokes the G1 character +set.

+ + +

SP

+ + +

Space.

+ + +

TAB

+ + +

Horizontal Tab (HT) (Ctrl-I).

+ + +

VT

+ + +

Vertical Tab (Ctrl-K). This is treated the +same as LF.

+ +

Controls +beginning with ESC
+This excludes controls where +ESC is part of a 7-bit +equivalent to 8-bit C1 controls, ordered by the final +character(s).

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +

ESC SP F

+ + +

7-bit controls (S7C1T).

+ + +

ESC SP G

+ + +

8-bit controls (S8C1T).

+ + +

ESC SP L

+ + +

Set ANSI conformance level 1 (dpANS +X3.134.1).

+ + +

ESC SP M

+ + +

Set ANSI conformance level 2 (dpANS +X3.134.1).

+ + +

ESC SP N

+ + +

Set ANSI conformance level 3 (dpANS +X3.134.1).

+ + +

ESC # 3

+ + +

DEC double-height line, top half +(DECDHL).

+ + +

ESC # 4

+ + +

DEC double-height line, bottom half +(DECDHL).

+ + +

ESC # 5

+ + +

DEC single-width line (DECSWL).

+ + +

ESC # 6

+ + +

DEC double-width line (DECDWL).

+ + +

ESC # 8

+ + +

DEC Screen Alignment Test (DECALN).

+ + +

ESC % @

+ + +

Select default character set. That is ISO +8859-1 (ISO 2022).

+ + +

ESC % G

+ + +

Select UTF-8 character set (ISO 2022).

+ + +

ESC ( +C

+ + +

Designate G0 Character Set (ISO 2022, +VT100).

+ +

Final character C for +designating 94-character sets. In this list, 0 , A and B +apply to VT100 and up, the remainder to VT220 and up: +
+C
= 0 → DEC Special Character and Line Drawing Set. +
+C
= A → United Kingdom (UK).
+C
= B → United States (USASCII).
+C
= 4 → Dutch.
+C
= C or 5 → Finnish.
+C
= R → French.
+C
= Q → French Canadian.
+C
= K → German.
+C
= Y → Italian.
+C
= E or 6 → Norwegian/Danish.
+C
= Z → Spanish.
+C
= H or 7 → Swedish.
+C
= = → Swiss.

+ + + + + + + +
+ + +

ESC ) +C

+ + +

Designate G1 Character Set (ISO 2022, +VT100).

+
+ +

The same character sets apply +as for ESC ( C.

+ + + + + + + +
+ + +

ESC * +C

+ + +

Designate G2 Character Set (ISO 2022, +VT220).

+
+ +

The same character sets apply +as for ESC ( C.

+ + + + + + + +
+ + +

ESC + +C

+ + +

Designate G3 Character Set (ISO 2022, +VT220).

+
+ +

The same character sets apply +as for ESC ( C.

+ + + + + + + +
+ + +

ESC - +C

+ + +

Designate G1 Character Set (VT300).

+
+ +

The same character sets apply +as for ESC ( C.

+ + + + + + + +
+ + +

ESC . +C

+ + +

Designate G2 Character Set (VT300).

+
+ +

The same character sets apply +as for ESC ( C.

+ + + + + + + +
+ + +

ESC / +C

+ + +

Designate G3 Character Set (VT300).

+
+ +

These work for 96-character +sets only.
+C
= A → ISO Latin-1 Supplemental.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +

ESC 6

+ + +

Back Index (DECBI), VT420 and up.

+ + +

ESC 7

+ + +

Save Cursor (DECSC).

+ + +

ESC 8

+ + +

Restore Cursor (DECRC).

+ + +

ESC 9

+ + +

Forward Index (DECFI), VT420 and up.

+ + +

ESC =

+ + +

Application Keypad (DECPAM).

+ + +

ESC >

+ + +

Normal Keypad (DECPNM).

+ + +

ESC F

+ + +

Cursor to lower left corner of screen. This +is enabled by the hpLowerleftBugCompat resource.

+ + +

ESC c

+ + +

Full Reset (RIS).

+ + +

ESC l

+ + +

Memory Lock (per HP terminals). Locks +memory above the cursor.

+ + +

ESC m

+ + +

Memory Unlock (per HP terminals).

+ + +

ESC n

+ + +

Invoke the G2 Character Set as GL +(LS2).

+ + +

ESC o

+ + +

Invoke the G3 Character Set as GL +(LS3).

+ + +

ESC |

+ + +

Invoke the G3 Character Set as GR +(LS3R).

+ + +

ESC }

+ + +

Invoke the G2 Character Set as GR +(LS2R).

+ + +

ESC ~

+ + +

Invoke the G1 Character Set as GR +(LS1R).

+ +

Application +Program-Control functions

+ + + + + + +
+ + +

APC P +t ST

+ + +

None. xterm implements no +APC functions; P +t is ignored. P t +need not be printable characters.

+ +

Device-Control +functions

+ + + + + +
+ + +

DCS P +s ; P s | P +t ST

+
+ +

User-Defined Keys (DECUDK). The +first parameter:
+P s
= 0 → Clear all UDK definitions +before starting (default).
+P s
= 1 → Erase Below (default). +
+The second parameter:
+P s
= 0 ← Lock the keys (default). +
+P s
= 1 ← Do not lock.
+The third parameter is a ’;’-separated list of +strings denoting the key-code separated by a ’/’ +from the hex-encoded key value. The key codes correspond to +the DEC function-key codes (e.g., F6=17).

+ + + + + +
+ + +

DCS $ q P +t ST

+
+ +

Request Status String +(DECRQSS). The string following the "q" is one of +the following:

+ + + + + +

“ q

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +

→ DECSCA
+“ p

+ + +

→ DECSCL
+r

+
+ + +

→ DECSTBM
+m

+
+ + +

→ SGR
+SP
q

+ + +

→ DECSCUSR

+ +

xterm responds with +DCS 1 $ r P +t ST for +valid requests, replacing the P t with +the corresponding CSI string, +or DCS 0 $ r P +t ST for +invalid requests.

+ + + + + +
+ + +

DCS + p P +t ST

+
+ +

Set Termcap/Terminfo Data +(xterm, experimental). The string following the +"p" is a name to use for retrieving data from the +terminal database. The data will be used for the +"tcap" keyboard configuration’s function- +and special-keys, as well as by the Request Termcap/Terminfo +String control.

+ + + + + +
+ + +

DCS + q P +t ST

+
+ +

Request Termcap/Terminfo String +(xterm, experimental). The string following the +"q" is a list of names encoded in hexadecimal (2 +digits per character) separated by ; which correspond to +termcap or terminfo key names.
+Two special features are also recognized, which are not key +names: Co for termcap colors (or colors for +terminfo colors), and TN for termcap name (or +name for terminfo name).
+xterm
responds with DCS 1 ++ r P t +ST for valid requests, adding +to P t an = , and the value of the +corresponding string that xterm would send, or +DCS 0 + r P +t ST for +invalid requests. The strings are encoded in hexadecimal (2 +digits per character).

+ +

Functions using +CSI , ordered by the final +character(s)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +

CSI P +s @

+ + +

Insert P s (Blank) +Character(s) (default = 1) (ICH).

+ + +

CSI P +s A

+ + +

Cursor Up P s Times +(default = 1) (CUU).

+ + +

CSI P +s B

+ + +

Cursor Down P s Times +(default = 1) (CUD).

+ + +

CSI P +s C

+ + +

Cursor Forward P s +Times (default = 1) (CUF).

+ + +

CSI P +s D

+ + +

Cursor Backward P s +Times (default = 1) (CUB).

+ + +

CSI P +s E

+ + +

Cursor Next Line P s +Times (default = 1) (CNL).

+ + +

CSI P +s F

+ + +

Cursor Preceding Line P +s Times (default = 1) (CPL).

+ + +

CSI P +s G

+ + +

Cursor Character Absolute [column] (default += [row,1]) (CHA).

+ + +

CSI P +s ; P

+
+ +

s H

+ + + + + + + + + + + + + + +
+ + +

Cursor Position [row;column] (default = +[1,1]) (CUP).

+ + +

CSI P +s I

+ + +

Cursor Forward Tabulation P +s tab stops (default = 1) (CHT).

+ + +

CSI P +s J

+ + +

Erase in Display (ED).

+ +

P s = 0 +→ Erase Below (default).
+P s
= 1 → Erase Above.
+P s
= 2 → Erase All.
+P s
= 3 → Erase Saved Lines +(xterm).

+ + + + + + +
+ + +

CSI ? P +s J

+ + +

Erase in Display (DECSED).

+
+ +

P s = 0 +→ Selective Erase Below (default).
+P s
= 1 → Selective Erase Above. +
+P s
= 2 → Selective Erase All.

+ + + + + + + +
+ + +

CSI P +s K

+ + +

Erase in Line (EL).

+
+ +

P s = 0 +→ Erase to Right (default).
+P s
= 1 → Erase to Left.
+P s
= 2 → Erase All.

+ + + + + + +
+ + +

CSI ? P +s K

+ + +

Erase in Line (DECSEL).

+
+ +

P s = 0 +→ Selective Erase to Right (default).
+P s
= 1 → Selective Erase to Left. +
+P s
= 2 → Selective Erase All.

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +

CSI P +s L

+ + +

Insert P s Line(s) +(default = 1) (IL).

+
+ + +

CSI P +s M

+ + +

Delete P s Line(s) +(default = 1) (DL).

+
+ + +

CSI P +s P

+ + +

Delete P s +Character(s) (default = 1) (DCH).

+
+ + +

CSI P +s S

+ + +

Scroll up P s lines +(default = 1) (SU).

+
+ + +

CSI P +s T

+ + +

Scroll down P s lines +(default = 1) (SD).

+
+ + +

CSI P +s ; P

+
+ +

s ; P +s ; P s ; P +s T

+ + + + + + + + + + +
+ + +

Initiate highlight mouse tracking. +Parameters are [func;startx;starty;firstrow;lastrow]. See +the section Mouse Tracking.

+ + +

CSI > P +s ;

+
+ +

P s T

+ + + + + +
+ + +

Reset one or more features of the title +modes to the default value. Normally, "reset" +disables the feature. It is possible to disable the ability +to reset features by compiling a different default for the +title modes into xterm.

+ +

P s = 0 +→ Do not set window/icon labels using hexadecimal. +
+P s
= 1 → Do not query window/icon +labels using hexadecimal.
+P s
= 2 → Do not set window/icon +labels using UTF-8.
+P s
= 3 → Do not query window/icon +labels using UTF-8. (See discussion of "Title +Modes").

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +

CSI P +s X

+ + +

Erase P s +Character(s) (default = 1) (ECH).

+ + +

CSI P +s Z

+ + +

Cursor Backward Tabulation P +s tab stops (default = 1) (CBT).

+ + +

CSI P +m `

+ + +

Character Position Absolute [column] +(default = [row,1]) (HPA).

+ + +

CSI P +m a

+ + +

Character Position Relative [columns] +(default = [row,col+1]) (HPR).

+ + +

CSI P +s b

+ + +

Repeat the preceding graphic character P +s times (REP).

+ + +

CSI P +s c

+ + +

Send Device Attributes (Primary DA).

+ +

P s = 0 +or omitted → request attributes from terminal. The +response depends on the decTerminalID resource +setting.
+→ CSI ? 1 ; 2 c +(‘‘VT100 with Advanced Video +Option’’)
+→ CSI ? 1 ; 0 c +(‘‘VT101 with No Options’’)
+→ CSI ? 6 c +(‘‘VT102’’)
+→ CSI ? 6 0 ; 1 ; 2 ; 6 ; +8 ; 9 ; 1 5 ; c (‘‘VT220’’)
+The VT100-style response parameters do not mean anything by +themselves. VT220 parameters do, telling the host what +features the terminal supports:
+P s
= 1 → 132-columns.
+P s
= 2 → Printer.
+P s
= 6 → Selective erase.
+P s
= 8 → User-defined keys.
+P s
= 9 → National replacement +character sets.
+P s
= 1 5 → Technical characters. +
+P s
= 2 2 → ANSI color, e.g., VT525. +
+P s
= 2 9 → ANSI text locator (i.e., +DEC Locator mode).

+ + + + + + +
+ + +

CSI > P +s c

+ + +

Send Device Attributes (Secondary DA).

+
+ +

P s = 0 +or omitted → request the terminal’s +identification code. The response depends on the +decTerminalID resource setting. It should apply only +to VT220 and up, but xterm extends this to VT100. +
+→ CSI > P +p ; P v ; P +c c
+where P p denotes the terminal type +
+P p
= 0 → +‘‘VT100’’.
+P p
= 1 → +‘‘VT220’’.
+and P v is the firmware version (for +xterm, this was originally the XFree86 patch number, +starting with 95). In a DEC terminal, P +c indicates the ROM cartridge +registration number and is always zero.

+ + + + + + + + + + + +
+ + +

CSI P +m d

+ + +

Line Position Absolute [row] (default = +[1,column]) (VPA).

+ + +

CSI P +m e

+ + +

Line Position Relative [rows] (default = +[row+1,column]) (VPR).

+ + +

CSI P +s ; P

+
+ +

s f

+ + + + + + + + + + +
+ + +

Horizontal and Vertical Position +[row;column] (default = [1,1]) (HVP).

+ + +

CSI P +s g

+ + +

Tab Clear (TBC).

+ +

P s = 0 +→ Clear Current Column (default).
+P s
= 3 → Clear All.

+ + + + + + + +
+ + +

CSI P +m h

+ + +

Set Mode (SM).

+
+ +

P s = 2 +→ Keyboard Action Mode (AM).
+P s
= 4 → Insert Mode (IRM).
+P s
= 1 2 → Send/receive (SRM). +
+P s
= 2 0 → Automatic Newline +(LNM).

+ + + + + + +
+ + +

CSI ? P +m h

+ + +

DEC Private Mode Set (DECSET).

+
+ +

P s = 1 +→ Application Cursor Keys (DECCKM).
+P s
= 2 → Designate USASCII for +character sets G0-G3 (DECANM), and set VT100 mode.
+P s
= 3 → 132 Column Mode (DECCOLM). +
+P s
= 4 → Smooth (Slow) Scroll +(DECSCLM).
+P s
= 5 → Reverse Video (DECSCNM). +
+P s
= 6 → Origin Mode (DECOM). +
+P s
= 7 → Wraparound Mode (DECAWM). +
+P s
= 8 → Auto-repeat Keys (DECARM). +
+P s
= 9 → Send Mouse X & Y on +button press. See the section Mouse Tracking.
+P s
= 1 0 → Show toolbar (rxvt). +
+P s
= 1 2 → Start Blinking Cursor +(att610).
+P s
= 1 8 → Print form feed +(DECPFF).
+P s
= 1 9 → Set print extent to full +screen (DECPEX).
+P s
= 2 5 → Show Cursor (DECTCEM). +
+P s
= 3 0 → Show scrollbar (rxvt). +
+P s
= 3 5 → Enable font-shifting +functions (rxvt).
+P s
= 3 8 → Enter Tektronix Mode +(DECTEK).
+P s
= 4 0 → Allow 80 → 132 +Mode.
+P s
= 4 1 → more(1) fix (see +curses resource).
+P s
= 4 2 → Enable Nation +Replacement Character sets (DECNRCM).
+P s
= 4 4 → Turn On Margin Bell. +
+P s
= 4 5 → Reverse-wraparound Mode. +
+P s
= 4 6 → Start Logging. This is +normally disabled by a compile-time option.
+P s
= 4 7 → Use Alternate Screen +Buffer. (This may be disabled by the titeInhibit +resource).
+P s
= 6 6 → Application keypad +(DECNKM).
+P s
= 6 7 → Backarrow key sends +backspace (DECBKM).
+P s
= 6 9 → Enable left and right +margin mode (DECLRMM), VT420 and up.
+P s
= 9 5 → Do not clear screen when +DECCOLM is set/reset (DECNCSM), VT510 and up.
+P s
= 1 0 0 0 → Send Mouse X & Y +on button press and release. See the section Mouse +Tracking.
+P s
= 1 0 0 1 → Use Hilite Mouse +Tracking.
+P s
= 1 0 0 2 → Use Cell Motion +Mouse Tracking.
+P s
= 1 0 0 3 → Use All Motion Mouse +Tracking.
+P s
= 1 0 0 4 → Send +FocusIn/FocusOut events.
+P s
= 1 0 0 5 → Enable UTF-8 Mouse +Mode.
+P s
= 1 0 0 6 → Enable SGR Mouse +Mode.
+P s
= 1 0 1 0 → Scroll to bottom on +tty output (rxvt).
+P s
= 1 0 1 5 → Enable urxvt Mouse +Mode.
+P s
= 1 0 1 1 → Scroll to bottom on +key press (rxvt).
+P s
= 1 0 3 4 → Interpret +"meta" key, sets eighth bit. (enables the +eightBitInput resource).
+P s
= 1 0 3 5 → Enable special +modifiers for Alt and NumLock keys. (This enables the +numLock resource).
+P s
= 1 0 3 6 → Send +ESC when Meta modifies a key. +(This enables the metaSendsEscape resource).
+P s
= 1 0 3 7 → Send DEL from the +editing-keypad Delete key.
+P s
= 1 0 3 9 → Send +ESC when Alt modifies a key. +(This enables the altSendsEscape resource).
+P s
= 1 0 4 0 → Keep selection even +if not highlighted. (This enables the keepSelection +resource).
+P s
= 1 0 4 1 → Use the CLIPBOARD +selection. (This enables the selectToClipboard +resource).
+P s
= 1 0 4 2 → Enable Urgency +window manager hint when Control-G is received. (This +enables the bellIsUrgent resource).
+P s
= 1 0 4 3 → Enable raising of +the window when Control-G is received. (enables the +popOnBell resource).
+P s
= 1 0 4 7 → Use Alternate Screen +Buffer. (This may be disabled by the titeInhibit +resource).
+P s
= 1 0 4 8 → Save cursor as in +DECSC. (This may be disabled by the titeInhibit +resource).
+P s
= 1 0 4 9 → Save cursor as in +DECSC and use Alternate Screen Buffer, clearing it first. +(This may be disabled by the titeInhibit resource). +This combines the effects of the 1 0 4 7 and 1 0 4 8 modes. +Use this with terminfo-based applications rather than the 4 +7 mode.
+P s
= 1 0 5 0 → Set terminfo/termcap +function-key mode.
+P s
= 1 0 5 1 → Set Sun function-key +mode.
+P s
= 1 0 5 2 → Set HP function-key +mode.
+P s
= 1 0 5 3 → Set SCO function-key +mode.
+P s
= 1 0 6 0 → Set legacy keyboard +emulation (X11R6).
+P s
= 1 0 6 1 → Set VT220 keyboard +emulation.
+P s
= 2 0 0 4 → Set bracketed paste +mode.

+ + + + + + + +
+ + +

CSI P +m i

+ + +

Media Copy (MC).

+
+ +

P s = 0 +→ Print screen (default).
+P s
= 4 → Turn off printer +controller mode.
+P s
= 5 → Turn on printer controller +mode.

+ + + + + + +
+ + +

CSI ? P +m i

+ + +

Media Copy (MC, DEC-specific).

+
+ +

P s = 1 +→ Print line containing cursor.
+P s
= 4 → Turn off autoprint mode. +
+P s
= 5 → Turn on autoprint mode. +
+P s
= 1 0 → Print composed display, +ignores DECPEX.
+P s
= 1 1 → Print all pages.

+ + + + + + + +
+ + +

CSI P +m l

+ + +

Reset Mode (RM).

+
+ +

P s = 2 +→ Keyboard Action Mode (AM).
+P s
= 4 → Replace Mode (IRM). +
+P s
= 1 2 → Send/receive (SRM). +
+P s
= 2 0 → Normal Linefeed +(LNM).

+ + + + + + +
+ + +

CSI ? P +m l

+ + +

DEC Private Mode Reset (DECRST).

+
+ +

P s = 1 +→ Normal Cursor Keys (DECCKM).
+P s
= 2 → Designate VT52 mode +(DECANM).
+P s
= 3 → 80 Column Mode (DECCOLM). +
+P s
= 4 → Jump (Fast) Scroll +(DECSCLM).
+P s
= 5 → Normal Video (DECSCNM). +
+P s
= 6 → Normal Cursor Mode +(DECOM).
+P s
= 7 → No Wraparound Mode +(DECAWM).
+P s
= 8 → No Auto-repeat Keys +(DECARM).
+P s
= 9 → Don’t send Mouse X +& Y on button press.
+P s
= 1 0 → Hide toolbar (rxvt). +
+P s
= 1 2 → Stop Blinking Cursor +(att610).
+P s
= 1 8 → Don’t print form +feed (DECPFF).
+P s
= 1 9 → Limit print to scrolling +region (DECPEX).
+P s
= 2 5 → Hide Cursor (DECTCEM). +
+P s
= 3 0 → Don’t show +scrollbar (rxvt).
+P s
= 3 5 → Disable font-shifting +functions (rxvt).
+P s
= 4 0 → Disallow 80 → 132 +Mode.
+P s
= 4 1 → No more(1) fix +(see curses resource).
+P s
= 4 2 → Disable Nation +Replacement Character sets (DECNRCM).
+P s
= 4 4 → Turn Off Margin Bell. +
+P s
= 4 5 → No Reverse-wraparound +Mode.
+P s
= 4 6 → Stop Logging. (This is +normally disabled by a compile-time option).
+P s
= 4 7 → Use Normal Screen +Buffer.
+P s
= 6 6 → Numeric keypad (DECNKM). +
+P s
= 6 7 → Backarrow key sends +delete (DECBKM).
+P s
= 6 9 → Disable left and right +margin mode (DECLRMM), VT420 and up.
+P s
= 9 5 → Clear screen when +DECCOLM is set/reset (DECNCSM), VT510 and up.
+P s
= 1 0 0 0 → Don’t send +Mouse X & Y on button press and release. See the section +Mouse Tracking.
+P s
= 1 0 0 1 → Don’t use +Hilite Mouse Tracking.
+P s
= 1 0 0 2 → Don’t use Cell +Motion Mouse Tracking.
+P s
= 1 0 0 3 → Don’t use All +Motion Mouse Tracking.
+P s
= 1 0 0 4 → Don’t send +FocusIn/FocusOut events.
+P s
= 1 0 0 5 → Disable UTF-8 Mouse +Mode.
+P s
= 1 0 0 6 → Disable SGR Mouse +Mode.
+P s
= 1 0 1 0 → Don’t scroll +to bottom on tty output (rxvt).
+P s
= 1 0 1 5 → Disable urxvt Mouse +Mode.
+P s
= 1 0 1 1 → Don’t scroll +to bottom on key press (rxvt).
+P s
= 1 0 3 4 → Don’t +interpret "meta" key. (This disables the +eightBitInput resource).
+P s
= 1 0 3 5 → Disable special +modifiers for Alt and NumLock keys. (This disables the +numLock resource).
+P s
= 1 0 3 6 → Don’t send +ESC when Meta modifies a key. +(This disables the metaSendsEscape resource).
+P s
= 1 0 3 7 → Send VT220 Remove +from the editing-keypad Delete key.
+P s
= 1 0 3 9 → Don’t send +ESC when Alt modifies a key. +(This disables the altSendsEscape resource).
+P s
= 1 0 4 0 → Do not keep +selection when not highlighted. (This disables the +keepSelection resource).
+P s
= 1 0 4 1 → Use the PRIMARY +selection. (This disables the selectToClipboard +resource).
+P s
= 1 0 4 2 → Disable Urgency +window manager hint when Control-G is received. (This +disables the bellIsUrgent resource).
+P s
= 1 0 4 3 → Disable raising of +the window when Control-G is received. (This disables the +popOnBell resource).
+P s
= 1 0 4 7 → Use Normal Screen +Buffer, clearing screen first if in the Alternate Screen. +(This may be disabled by the titeInhibit resource). +
+P s
= 1 0 4 8 → Restore cursor as in +DECRC. (This may be disabled by the titeInhibit +resource).
+P s
= 1 0 4 9 → Use Normal Screen +Buffer and restore cursor as in DECRC. (This may be disabled +by the titeInhibit resource). This combines the +effects of the 1 0 4 7 and 1 0 4 8 modes. Use this with +terminfo-based applications rather than the 4 7 mode. +
+P s
= 1 0 5 0 → Reset +terminfo/termcap function-key mode.
+P s
= 1 0 5 1 → Reset Sun +function-key mode.
+P s
= 1 0 5 2 → Reset HP +function-key mode.
+P s
= 1 0 5 3 → Reset SCO +function-key mode.
+P s
= 1 0 6 0 → Reset legacy +keyboard emulation (X11R6).
+P s
= 1 0 6 1 → Reset keyboard +emulation to Sun/PC style.
+P s
= 2 0 0 4 → Reset bracketed +paste mode.

+ + + + + + + +
+ + +

CSI P +m m

+ + +

Character Attributes (SGR).

+
+ +

P s = 0 +→ Normal (default).
+P s
= 1 → Bold.
+P s
= 4 → Underlined.
+P s
= 5 → Blink (appears as Bold). +
+P s
= 7 → Inverse.
+P s
= 8 → Invisible, i.e., hidden +(VT300).
+P s
= 2 2 → Normal (neither bold nor +faint).
+P s
= 2 4 → Not underlined.
+P s
= 2 5 → Steady (not blinking). +
+P s
= 2 7 → Positive (not inverse). +
+P s
= 2 8 → Visible, i.e., not +hidden (VT300).
+P s
= 3 0 → Set foreground color to +Black.
+P s
= 3 1 → Set foreground color to +Red.
+P s
= 3 2 → Set foreground color to +Green.
+P s
= 3 3 → Set foreground color to +Yellow.
+P s
= 3 4 → Set foreground color to +Blue.
+P s
= 3 5 → Set foreground color to +Magenta.
+P s
= 3 6 → Set foreground color to +Cyan.
+P s
= 3 7 → Set foreground color to +White.
+P s
= 3 9 → Set foreground color to +default (original).
+P s
= 4 0 → Set background color to +Black.
+P s
= 4 1 → Set background color to +Red.
+P s
= 4 2 → Set background color to +Green.
+P s
= 4 3 → Set background color to +Yellow.
+P s
= 4 4 → Set background color to +Blue.
+P s
= 4 5 → Set background color to +Magenta.
+P s
= 4 6 → Set background color to +Cyan.
+P s
= 4 7 → Set background color to +White.
+P s
= 4 9 → Set background color to +default (original).

+ +

If 16-color +support is compiled, the following apply. Assume that +xterm’s resources are set so that the ISO color +codes are the first 8 of a set of 16. Then the +aixterm colors are the bright versions of the ISO +colors:
+P s
= 9 0 → Set foreground color to +Black.
+P s
= 9 1 → Set foreground color to +Red.
+P s
= 9 2 → Set foreground color to +Green.
+P s
= 9 3 → Set foreground color to +Yellow.
+P s
= 9 4 → Set foreground color to +Blue.
+P s
= 9 5 → Set foreground color to +Magenta.
+P s
= 9 6 → Set foreground color to +Cyan.
+P s
= 9 7 → Set foreground color to +White.
+P s
= 1 0 0 → Set background color +to Black.
+P s
= 1 0 1 → Set background color +to Red.
+P s
= 1 0 2 → Set background color +to Green.
+P s
= 1 0 3 → Set background color +to Yellow.
+P s
= 1 0 4 → Set background color +to Blue.
+P s
= 1 0 5 → Set background color +to Magenta.
+P s
= 1 0 6 → Set background color +to Cyan.
+P s
= 1 0 7 → Set background color +to White.

+ +

If xterm +is compiled with the 16-color support disabled, it supports +the following, from rxvt:
+P s
= 1 0 0 → Set foreground and +background color to default.

+ +

If 88- or +256-color support is compiled, the following apply.
+P s
= 3 8 ; 5 ; P s +→ Set foreground color to the second P +s .
+P s
= 4 8 ; 5 ; P s +→ Set background color to the second P +s .

+ + + + + +
+ + + +

CSI +> P s ; P s +m

+
+ +

Set or reset resource-values +used by xterm to decide whether to construct escape +sequences holding information about the modifiers pressed +with a given key. The first parameter identifies the +resource to set/reset. The second parameter is the value to +assign to the resource. If the second parameter is omitted, +the resource is reset to its initial value.
+P s
= 1 → modifyCursorKeys.
+P s
= 2 → modifyFunctionKeys. +
+P s
= 4 → modifyOtherKeys.
+If no parameters are given, all resources are reset to their +initial values.

+ + + + + + + +
+ + +

CSI P +s n

+ + +

Device Status Report (DSR).

+
+ +

P s = 5 +→ Status Report. Result +(‘‘OK’’) is
+CSI
0 n
+P s
= 6 → Report Cursor Position +(CPR) [row;column]. Result is
+CSI
r ; c R

+ + + + + +
+ + +

CSI > P +s n

+ + +

Disable modifiers which may be enabled via +the CSI > P +s ; P s m sequence. +This corresponds to a resource value of "-1", +which cannot be set with the other sequence. The parameter +identifies the resource to be disabled:

+ +

P s = 1 +→ modifyCursorKeys.
+P s
= 2 → modifyFunctionKeys. +
+P s
= 4 → modifyOtherKeys.
+If the parameter is omitted, modifyFunctionKeys is +disabled. When modifyFunctionKeys is disabled, +xterm uses the modifier keys to make an extended +sequence of functions rather than adding a parameter to each +function key to denote the modifiers.

+ + + + + + +
+ + +

CSI ? P +s n

+ + +

Device Status Report (DSR, +DEC-specific).

+
+ +

P s = 6 +→ Report Cursor Position (DECXCPR) [row;column] as +CSI ? r ; c R +(assumes the default page, i.e., "1").
+P s
= 1 5 → Report Printer status as +CSI ? 1 0 n (ready). or +CSI ? 1 1 n (not ready). +
+P s
= 2 5 → Report UDK status as +CSI ? 2 0 n (unlocked) or +CSI ? 2 1 n (locked).
+P s
= 2 6 → Report Keyboard status +as
+CSI
? 2 7 ; 1 ; 0 ; 0 n (North American). +
+The last two parameters apply to VT400 & up, and denote +keyboard ready and LK01 respectively.
+P s
= 5 3 → Report Locator status as +CSI ? 5 3 n Locator available, +if compiled-in, or CSI ? 5 0 n +No Locator, if not.
+P s
= 6 2 → Report macro space +(DECMSR) as CSI P +n \* {
+P s
= 6 3 → Report memory checksum +(DECCKSR) as DCS P +t ! x x x x +ST
+P t
is the request id (from an optional +parameter to the request).
+The x’s are hexadecimal digits 0-9 and A-F.
+P s
= 7 5 → Report data integrity as +CSI ? 7 0 n (ready, no errors) +
+P s
= 8 5 → Report multi-session +configuration as CSI ? 8 3 n +(not configured for multiple-session operation).

+ + + + + +
+ + +

CSI > P +s p

+ + +

Set resource value pointerMode. This +is used by xterm to decide whether to hide the +pointer cursor as the user types. Valid values for the +parameter:

+ +

P s = 0 +→ never hide the pointer.
+P s
= 1 → hide if the mouse tracking +mode is not enabled.
+P s
= 2 → always hide the pointer. +If no parameter is given, xterm uses the default, +which is 1 .

+ + + + + + + + +
+ + +

CSI ! p

+ + +

Soft terminal reset (DECSTR).

+ + +

CSI P +s $ p

+ + +

Request ANSI mode (DECRQM). For VT300 and +up, reply is

+ + +

CSI +P s ; P m $ y +
+where P s is the mode number as in RM, +and P m is the mode value:
+0 - not recognized
+1 - set
+2 - reset
+3 - permanently set
+4 - permanently reset

+ + + + + +
+ + +

CSI ? P +s $ p

+
+ +

Request DEC private mode +(DECRQM). For VT300 and up, reply is
+CSI
? P s ; P +m $ p
+where P s is the mode number as in +DECSET, P m is the mode value as in +the ANSI DECRQM.

+ + + + + +
+ + +

CSI P +s ; P s “ +p

+
+ +

Set conformance level (DECSCL). +Valid values for the first parameter:
+P s
= 6 1 → VT100.
+P s
= 6 2 → VT200.
+P s
= 6 3 → VT300.
+Valid values for the second parameter:
+P s
= 0 → 8-bit controls.
+P s
= 1 → 7-bit controls (always set +for VT100).
+P s
= 2 → 8-bit controls.

+ + + + + + + +
+ + +

CSI P +s q

+ + +

Load LEDs (DECLL).

+
+ +

P s = 0 +→ Clear all LEDS (default).
+P s
= 1 → Light Num Lock.
+P s
= 2 → Light Caps Lock.
+P s
= 3 → Light Scroll Lock.
+P s
= 2 1 → Extinguish Num Lock. +
+P s
= 2 2 → Extinguish Caps Lock. +
+P s
= 2 3 → Extinguish Scroll +Lock.

+ + + + + +
+ + +

CSI P +s SP q

+
+ +

Set cursor style (DECSCUSR, +VT520).
+P s
= 0 → blinking block.
+P s
= 1 → blinking block (default). +
+P s
= 2 → steady block.
+P s
= 3 → blinking underline. +
+P s
= 4 → steady underline.

+ + + + + +
+ + +

CSI P +s “ q

+ + +

Select character protection attribute +(DECSCA). Valid values for the parameter:

+ +

P s = 0 +→ DECSED and DECSEL can erase (default).
+P s
= 1 → DECSED and DECSEL cannot +erase.
+P s
= 2 → DECSED and DECSEL can +erase.

+ + + + + +
+ + +

CSI P +s ; P s r

+
+ +

Set Scrolling Region +[top;bottom] (default = full size of window) (DECSTBM).

+ + + + + + + + +
+ + +

CSI ? P +m r

+ + +

Restore DEC Private Mode Values. The value +of P s previously saved is restored. +P s values are the same as for +DECSET.

+ + +

CSI P +t ; P l

+
+ +

; P b ; P +r ; P s $ r

+ + + + + +
+ + +

Change Attributes in Rectangular Area +(DECCARA), VT400 and up.

+ +

P t ; +P l ; P b ; P +r denotes the rectangle.
+P s
denotes the SGR attributes to change: +0, 1, 4, 5, 7.

+ + + + + +
+ + +

CSI P +l ; P r s

+
+ +

Set left and right margins +(DECSLRM), available only when DECLRMM is enabled (VT420 and +up).

+ + + + + + + + + + + +
+ + +

CSI s

+ + +

Save cursor (ANSI.SYS), available only when +DECLRMM is disabled.

+ + +

CSI ? P +m s

+ + +

Save DEC Private Mode Values. P +s values are the same as for DECSET.

+ + +

CSI P +s ; P

+
+ +

s ; P +s t

+ + + + + +
+ + +

Window manipulation (from dtterm, as +well as extensions). These controls may be disabled using +the allowWindowOps resource. Valid values for the +first (and any additional parameters) are:

+ +

P s = 1 +→ De-iconify window.
+P s
= 2 → Iconify window.
+P s
= 3 ; x ; y → Move window +to [x, y].
+P s
= 4 ; height ; width → +Resize the xterm window to given height and width in +pixels. Omitted parameters reuse the current height or +width. Zero parameters use the display’s height or +width.
+P s
= 5 → Raise the xterm +window to the front of the stacking order.
+P s
= 6 → Lower the xterm +window to the bottom of the stacking order.
+P s
= 7 → Refresh the xterm +window.
+P s
= 8 ; height ; width → +Resize the text area to given height and width in +characters. Omitted parameters reuse the current height or +width. Zero parameters use the display’s height or +width.
+P s
= 9 ; 0 → Restore maximized +window.
+P s
= 9 ; 1 → Maximize window (i.e., +resize to screen size).
+P s
= 1 0 ; 0 → Undo full-screen +mode.
+P s
= 1 0 ; 1 → Change to +full-screen.
+P s
= 1 1 → Report xterm +window state. If the xterm window is open +(non-iconified), it returns +CSI 1 t . If the xterm +window is iconified, it returns +CSI 2 t .
+P s
= 1 3 → Report xterm +window position. Result is CSI +3 ; x ; y t
+P s
= 1 4 → Report xterm +window in pixels. Result is +CSI 4 ; height ; +width t
+P s
= 1 8 → Report the size of the +text area in characters. Result is +CSI 8 ; height ; +width t
+P s
= 1 9 → Report the size of the +screen in characters. Result is +CSI 9 ; height ; +width t
+P s
= 2 0 → Report xterm +window’s icon label. Result is +OSC L label +ST
+P s
= 2 1 → Report xterm +window’s title. Result is +OSC l label +ST
+P s
= 2 2 ; 0 → Save xterm +icon and window title on stack.
+P s
= 2 2 ; 1 → Save xterm +icon title on stack.
+P s
= 2 2 ; 2 → Save xterm +window title on stack.
+P s
= 2 3 ; 0 → Restore xterm +icon and window title from stack.
+P s
= 2 3 ; 1 → Restore xterm +icon title from stack.
+P s
= 2 3 ; 2 → Restore xterm +window title from stack.
+P s
>= 2 4 → Resize to P +s lines (DECSLPP).

+ + + + + +
+ + +

CSI P +t ; P l ; P +b ; P r ; P +s $ t

+
+ +

Reverse Attributes in +Rectangular Area (DECRARA), VT400 and up.
+P t
; P l ; P +b ; P r denotes the +rectangle.
+P s
denotes the attributes to reverse, +i.e., 1, 4, 5, 7.

+ + + + + +
+ + +

CSI > P +s ; P s t

+
+ +

Set one or more features of the +title modes. Each parameter enables a single feature. +
+P s
= 0 → Set window/icon labels +using hexadecimal.
+P s
= 1 → Query window/icon labels +using hexadecimal.
+P s
= 2 → Set window/icon labels +using UTF-8.
+P s
= 3 → Query window/icon labels +using UTF-8. (See discussion of "Title Modes")

+ + + + + +
+ + +

CSI P +s SP t

+
+ +

Set warning-bell volume +(DECSWBV, VT520).
+P s
= 0 or 1 → off.
+P s
= 2 , 3 or 4 → low.
+P s
= 5 , 6 , 7 , or 8 → high.

+ + + + + + + + + + + + +
+ + +

CSI u

+ + +

Restore cursor (ANSI.SYS).

+
+ + +

CSI P +s SP

+
+ +

u

+ + + + + + +
+ + +

Set margin-bell volume (DECSMBV, +VT520).

+
+ +

P s = 1 +→ off.
+P s
= 2 , 3 or 4 → low.
+P s
= 0 , 5 , 6 , 7 , or 8 → +high.

+ + + + + +
+ + +

CSI P +t ; P l ; P +b ; P r ; P +p ; P t ; P +l ; P p $ v

+
+ +

Copy Rectangular Area (DECCRA, +VT400 and up).
+P t
; P l ; P +b ; P r denotes the +rectangle.
+P p
denotes the source page.
+P t
; P l denotes +the target location.
+P p
denotes the target page.

+ + + + + +
+ + +

CSI P +t ; P l ; P +b ; P r ’ +w

+
+ +

Enable Filter Rectangle +(DECEFR), VT420 and up.
+Parameters are [top;left;bottom;right].
+Defines the coordinates of a filter rectangle and activates +it. Anytime the locator is detected outside of the filter +rectangle, an outside rectangle event is generated and the +rectangle is disabled. Filter rectangles are always treated +as "one-shot" events. Any parameters that are +omitted default to the current locator position. If all +parameters are omitted, any locator motion will be reported. +DECELR always cancels any prevous rectangle definition.

+ + + + + + + +
+ + +

CSI P +s x

+ + +

Request Terminal Parameters +(DECREQTPARM).

+
+ +

if P s is +a "0" (default) or "1", and xterm +is emulating VT100, the control sequence elicits a response +of the same form whose parameters describe the terminal: +
+P s
→ the given P +s incremented by 2.
+P n
= 1 ← no parity.
+P n
= 1 ← eight bits.
+P n
= 1 ← 2 8 transmit 38.4k baud. +
+P n
= 1 ← 2 8 receive 38.4k baud. +
+P n
= 1 ← clock multiplier.
+P n
= 0 ← STP flags.

+ + + + + + +
+ + +

CSI P +s * x

+ + +

Select Attribute Change Extent +(DECSACE).

+
+ +

P s = 0 +→ from start to end position, wrapped.
+P s
= 1 → from start to end +position, wrapped.
+P s
= 2 → rectangle (exact).

+ + + + + +
+ + +

CSI P +i ; P g ; P +t ; P l ; P +b ; P r * y

+
+ +

Request Checksum of Rectangular +Area (DECRQCRA), VT420 and up. Response is +
+DCS
P t ! x x x x +ST
+P i
is the request id.
+P g
is the page number.
+P t
; P l ; P +b ; P r denotes the +rectangle.
+The x’s are hexadecimal digits 0-9 and A-F.

+ + + + + +
+ + +

CSI P +c ; P t ; P +l ; P b ; P +r $ x

+
+ +

Fill Rectangular Area (DECFRA), +VT420 and up.
+P c
is the character to use.
+P t
; P l ; P +b ; P r denotes the +rectangle.

+ + + + + +
+ + +

CSI P +s ; P u ’ +z

+
+ +

Enable Locator Reporting +(DECELR).
+Valid values for the first parameter:
+P s
= 0 → Locator disabled +(default).
+P s
= 1 → Locator enabled.
+P s
= 2 → Locator enabled for one +report, then disabled.
+The second parameter specifies the coordinate unit for +locator reports.
+Valid values for the second parameter:
+P u
= 0 ← or omitted → default +to character cells.
+P u
= 1 ← device physical pixels. +
+P u
= 2 ← character cells.

+ + + + + +
+ + +

CSI P +t ; P l ; P +b ; P r $ z

+
+ +

Erase Rectangular Area +(DECERA), VT400 and up.
+P t
; P l ; P +b ; P r denotes the +rectangle.

+ + + + + + +
+ + +

CSI P +m ’ {

+ + +

Select Locator Events (DECSLE).

+
+ +

Valid values for the first (and +any additional parameters) are:
+P s
= 0 → only respond to explicit +host requests (DECRQLP).
+(This is default). It also cancels any filter
+rectangle.
+P s
= 1 → report button down +transitions.
+P s
= 2 → do not report button down +transitions.
+P s
= 3 → report button up +transitions.
+P s
= 4 → do not report button up +transitions.

+ + + + + +
+ + +

CSI P +t ; P l ; P +b ; P r $ {

+
+ +

Selective Erase Rectangular +Area (DECSERA), VT400 and up.
+P t
; P l ; P +b ; P r denotes the +rectangle.

+ + + + + + +
+ + +

CSI P +s ’ |

+ + +

Request Locator Position (DECRQLP).

+
+ +

Valid values for the parameter +are:
+P s
= 0 , 1 or omitted → transmit a +single DECLRP locator report.

+ +

If Locator +Reporting has been enabled by a DECELR, xterm will respond +with a DECLRP Locator Report. This report is also generated +on button up and down events if they have been enabled with +a DECSLE, or when the locator is detected outside of a +filter rectangle, if filter rectangles have been enabled +with a DECEFR.

+ +

→ +CSI P e +; P b ; P r ; +P c ; P p & +w

+ +

Parameters are +[event;button;row;column;page].
+Valid values for the event:
+P e
= 0 → locator unavailable - no +other parameters sent.
+P e
= 1 → request - xterm received a +DECRQLP.
+P e
= 2 → left button down.
+P e
= 3 → left button up.
+P e
= 4 → middle button down. +
+P e
= 5 → middle button up.
+P e
= 6 → right button down.
+P e
= 7 → right button up.
+P e
= 8 → M4 button down.
+P e
= 9 → M4 button up.
+P e
= 1 0 → locator outside filter +rectangle.
+‘‘button’’ parameter is a bitmask +indicating which buttons are pressed:
+P b
= 0 ← no buttons down.
+P b
& 1 ← right button down. +
+P b
& 2 ← middle button down. +
+P b
& 4 ← left button down. +
+P b
& 8 ← M4 button down.
+‘‘row’’ and +‘‘column’’ parameters are the +coordinates of the locator position in the xterm window, +encoded as ASCII decimal.
+The ‘‘page’’ parameter is not used +by xterm, and will be omitted.

+ + + + + +
+ + +

CSI P +m SP }

+
+ +

Insert P +s Column(s) (default = 1) (DECIC), VT420 +and up.

+ + + + + +
+ + +

CSI P +m SP ~

+
+ +

Delete P +s Column(s) (default = 1) (DECDC), VT420 +and up.

+ +

Operating System +Controls

+ + + + + + + + +
+ + +

OSC P +s ; P t +ST

+
+ + +

OSC P +s ; P t +BEL

+
+ +

Set Text Parameters. For colors +and font, if P t is a "?", +the control sequence elicits a response which consists of +the control sequence which would set the corresponding +value. The dtterm control sequences allow you to +determine the icon name and window title.
+P s
= 0 → Change Icon Name and +Window Title to P t .
+P s
= 1 → Change Icon Name to P +t .
+P s
= 2 → Change Window Title to +P t .
+P s
= 3 → Set X property on +top-level window. P t should be in the +form "prop=value", or just +"prop" to delete the property
+P s
= 4 ; c ; spec → Change +Color Number c to the color specified by spec. +This can be a name or RGB specification as per +XParseColor. Any number of c name pairs may be +given. The color numbers correspond to the ANSI colors 0-7, +their bright versions 8-15, and if supported, the remainder +of the 88-color or 256-color table.

+ +

If a +"?" is given rather than a name or RGB +specification, xterm replies with a control sequence of the +same form which can be used to set the corresponding color. +Because more than one pair of color number and specification +can be given in one control sequence, xterm can make +more than one reply.

+ +

P +s = 5 ; c ; spec → Change +Special Color Number c to the color specified by +spec. This can be a name or RGB specification as per +XParseColor. Any number of c name pairs may be +given. The special colors can also be set by adding the +maximum number of colors to these codes in an +OSC 4 control:

+ +

P +c = 0 ← resource colorBD +(BOLD).
+P c
= 1 ← resource colorUL +(UNDERLINE).
+P c
= 2 ← resource colorBL +(BLINK).
+P c
= 3 ← resource colorRV +(REVERSE).

+ +

The 10 colors +(below) which may be set or queried using 1 0 through 1 9 +are denoted dynamic colors, since the corresponding +control sequences were the first means for setting +xterm’s colors dynamically, i.e., after it was +started. They are not the same as the ANSI colors. These +controls may be disabled using the allowColorOps +resource. At least one parameter is expected for P +t . Each successive parameter changes the +next color in the list. The value of P +s tells the starting point in the list. +The colors are specified by name or RGB specification as per +XParseColor.

+ +

If a +"?" is given rather than a name or RGB +specification, xterm replies with a control sequence of the +same form which can be used to set the corresponding dynamic +color. Because more than one pair of color number and +specification can be given in one control sequence, +xterm can make more than one reply.

+ +

P +s = 1 0 → Change VT100 text +foreground color to P t .
+P s
= 1 1 → Change VT100 text +background color to P t .
+P s
= 1 2 → Change text cursor color +to P t .
+P s
= 1 3 → Change mouse foreground +color to P t .
+P s
= 1 4 → Change mouse background +color to P t .
+P s
= 1 5 → Change Tektronix +foreground color to P t .
+P s
= 1 6 → Change Tektronix +background color to P t .
+P s
= 1 7 → Change highlight +background color to P t .
+P s
= 1 8 → Change Tektronix cursor +color to P t .
+P s
= 1 9 → Change highlight +foreground color to P t .

+ +

P +s = 4 6 → Change Log File to P +t . (This is normally disabled by a +compile-time option).

+ +

P +s = 5 0 → Set Font to P +t . These controls may be disabled using +the allowFontOps resource. If P +t begins with a "#", index in +the font menu, relative (if the next character is a plus or +minus sign) or absolute. A number is expected but not +required after the sign (the default is the current entry +for relative, zero for absolute indexing).
+The same rule (plus or minus sign, optional number) is used +when querying the font. The remainder of P +t is ignored.
+A font can be specified after a "#" index +expression, by adding a space and then the font specifier. +
+If the "TrueType Fonts" menu entry is set (the +renderFont resource), then this control sets/queries +the faceName resource.

+ +

P +s = 5 1 (reserved for Emacs shell).

+ +

P +s = 5 2 → Manipulate Selection Data. +These controls may be disabled using the +allowWindowOps resource. The parameter P +t is parsed as

+ + + + + +
+ + +

P c ; P +d

+ +

The first, P +c , may contain zero or more characters +from the set c p s 0 1 2 3 4 5 6 7 . It is used to construct +a list of selection parameters for clipboard, primary, +select, or cut buffers 0 through 7 respectively, in the +order given. If the parameter is empty, xterm uses s +0 , to specify the configurable primary/clipboard selection +and cut buffer 0.
+The second parameter, P d , gives the +selection data. Normally this is a string encoded in base64. +The data becomes the new selection, which is then available +for pasting by other applications.
+If the second parameter is a ? , xterm replies to the +host with the selection data encoded using the same +protocol.
+If the second parameter is neither a base64 string nor ? , +then the selection is cleared.

+ +

P +s = 1 0 4 ; c → Reset Color +Number c. It is reset to the color specified by the +corresponding X resource. Any number of c parameters +may be given. These parameters correspond to the ANSI colors +0-7, their bright versions 8-15, and if supported, the +remainder of the 88-color or 256-color table. If no +parameters are given, the entire table will be reset.

+ +

P +s = 1 0 5 ; c → Reset Special +Color Number c. It is reset to the color specified by +the corresponding X resource. Any number of c +parameters may be given. These parameters correspond to the +special colors which can be set using an +OSC 5 control (or by adding +the maximum number of colors using an +OSC 4 control).

+ +

The dynamic +colors can also be reset to their default (resource) +values:
+P s
= 1 1 0 → Reset VT100 text +foreground color.
+P s
= 1 1 1 → Reset VT100 text +background color.
+P s
= 1 1 2 → Reset text cursor +color.
+P s
= 1 1 3 → Reset mouse foreground +color.
+P s
= 1 1 4 → Reset mouse background +color.
+P s
= 1 1 5 → Reset Tektronix +foreground color.
+P s
= 1 1 6 → Reset Tektronix +background color.
+P s
= 1 1 7 → Reset highlight color. +
+P s
= 1 1 8 → Reset Tektronix cursor +color.

+ +

Privacy +Message

+ + + + + + +
+ + +

PM P +t ST

+ + +

xterm implements no +PM functions; P +t is ignored. P t +need not be printable characters.

+ + +

Alt and Meta Keys

+ + +

Many keyboards have +keys labeled "Alt". Few have keys labeled +"Meta". However, xterm’s default +translations use the Meta modifier. Common keyboard +configurations assign the Meta modifier to an +"Alt" key. By using xmodmap one may have +the modifier assigned to a different key, and have +"real" alt and meta keys. Here is an example:

+ +

! put meta on +mod3 to distinguish it from alt
+keycode 64 = Alt_L
+clear mod1
+add mod1 = Alt_L
+keycode 115 = Meta_L
+clear mod3
+add mod3 = Meta_L

+ +

The +metaSendsEscape resource (and altSendsEscape +if altIsNotMeta is set) can be used to control the +way the Meta modifier applies to ordinary keys unless +the modifyOtherKeys resource is set:

+ +

- prefix a key with the +ESC character.
+- shift the key from codes 0-127 to 128-255 by adding +128.

+ +

The table shows the +result for a given character "x" with modifiers +according to the default translations with the resources set +on or off. This assumes altIsNotMeta is set:

+ + +

Image grohtml-285551.png

+ + +

PC-Style Function Keys

+ + +

If xterm +does minimal translation of the function keys, it usually +does this with a PC-style keyboard, so PC-style function +keys result. Sun keyboards are similar to PC keyboards. Both +have cursor and scrolling operations printed on the keypad, +which duplicate the smaller cursor and scrolling +keypads.

+ +

X does not +predefine NumLock (used for VT220 keyboards) or Alt (used as +an extension for the Sun/PC keyboards) as modifiers. These +keys are recognized as modifiers when enabled by the +numLock resource, or by the "DECSET 1 0 3 5 +" control sequence.

+ +

The cursor keys +transmit the following escape sequences depending on the +mode specified via the DECCKM escape sequence.

+ + +

Image grohtml-285552.png

+ +

The home- and end-keys (unlike PageUp and +other keys also on the 6-key editing keypad) are considered +"cursor keys" by xterm. Their mode is also +controlled by the DECCKM escape sequence:

+ + +

Image grohtml-285553.png

+ +

The application +keypad transmits the following escape sequences depending on +the mode specified via the DECPNM and DECPAM +escape sequences. Use the NumLock key to override the +application mode.

+ +

Not all keys are +present on the Sun/PC keypad (e.g., PF1, Tab), but are +supported by the program.

+ + +

Image grohtml-285554.png

+ +

They also provide 12 function keys, as well +as a few other special-purpose keys:

+ + +

Image grohtml-285555.png

+ +

Older versions of +xterm implement different escape sequences for F1 +through F4. These can be activated by setting the +oldXtermFKeys resource. However, since they do not +correspond to any hardware terminal, they have been +deprecated. (The DEC VT220 reserves F1 through F5 for local +functions such as Setup).

+ + +

Image grohtml-285556.png

+ +

In normal mode, i.e., a Sun/PC keyboard +when the sunKeyboard resource is false, xterm +recognizes function key modifiers which are parameters +appended before the final character of the control +sequence.

+ + +

Image grohtml-285557.png

+ +

For example, shift-F5 would be sent as +CSI 1 5 ; 2 ~

+ +

If the +alwaysUseMods resource is set, the Meta modifier also +is recognized, making parameters 9 through 16.

+ + +

VT220-Style Function Keys

+ + +

However, +xterm is most useful as a DEC VT102 or VT220 +emulator. Set the sunKeyboard resource to true to +force a Sun/PC keyboard to act like a VT220 keyboard.

+ +

The VT102/VT220 +application keypad transmits unique escape sequences in +application mode, which are distinct from the cursor and +scrolling keypad:

+ + +

Image grohtml-285558.png

+ +

The VT220 provides a 6-key editing keypad, +which is analogous to that on the PC keyboard. It is not +affected by DECCKM or +DECPNM/DECPAM:

+ + +

Image grohtml-285559.png

+ +

The VT220 provides 8 additional function +keys. With a Sun/PC keyboard, access these keys by +Control/F1 for F13, etc.

+ + +

Image grohtml-2855510.png

+ + +

VT52-Style Function Keys

+ + +

A VT52 does not +have function keys, but it does have a numeric keypad and +cursor keys. They differ from the other emulations by the +prefix. Also, the cursor keys do not change:

+ + +

Image grohtml-2855511.png

+ +

The keypad is similar:

+ + +

Image grohtml-2855512.png

+ + +

Sun-Style Function Keys

+ + +

The xterm +program provides support for Sun keyboards more directly, by +a menu toggle that causes it to send Sun-style function key +codes rather than VT220. Note, however, that the sun +and VT100 emulations are not really compatible. For +example, their wrap-margin behavior differs.

+ +

Only function keys +are altered; keypad and cursor keys are the same. The +emulation responds identically. See the xterm-sun terminfo +entry for details.

+ + +

HP-Style Function Keys

+ + +

Similarly, +xterm can be compiled to support HP keyboards. See +the xterm-hp terminfo entry for details.

+ + +

The Alternate Screen Buffer

+ + +

Xterm +maintains two screen buffers. The normal screen buffer +allows you to scroll back to view saved lines of output up +to the maximum set by the saveLines resource. The +alternate screen buffer is exactly as large as the display, +contains no additional saved lines. When the alternate +screen buffer is active, you cannot scroll back to view +saved lines. Xterm provides control sequences and +menu entries for switching between the two.

+ +

Most full-screen +applications use terminfo or termcap to obtain strings used +to start/stop full-screen mode, i.e., smcup and +rmcup for terminfo, or the corresponding ti +and te for termcap. The titeInhibit resource +removes the ti and te strings from the TERMCAP +string which is set in the environment for some platforms. +That is not done when xterm is built with terminfo +libraries because terminfo does not provide the whole text +of the termcap data in one piece. It would not work for +terminfo anyway, since terminfo data is not passed in +environment variables; setting an environment variable in +this manner would have no effect on the application’s +ability to switch between normal and alternate screen +buffers. Instead, the newer private mode controls (such as 1 +0 4 9 ) for switching between normal and alternate screen +buffers simply disable the switching. They add other +features such as clearing the display for the same reason: +to make the details of switching independent of the +application that requests the switch.

+ + +

Bracketed Paste Mode

+ + +

When bracketed +paste mode is set, pasted text is bracketed with control +sequences so that the program can differentiate pasted text +from typed-in text. When bracketed paste mode is set, the +program will receive:
+ESC
[ 200 ~,
+followed by the pasted text, followed by
+ESC
[ 201 ~.

+ + +

Title Modes

+ + +

The window- and +icon-labels can be set or queried using control sequences. +As a VT220-emulator, xterm "should" limit +the character encoding for the corresponding strings to +ISO-8859-1. Indeed, it used to be the case (and was +documented) that window titles had to be ISO-8859-1. This is +no longer the case. However, there are many applications +which still assume that titles are set using ISO-8859-1. So +that is the default behavior.

+ +

If xterm is +running with UTF-8 encoding, it is possible to use window- +and icon-labels encoded using UTF-8. That is because the +underlying X libraries (and many, but not all) window +managers support this feature.

+ +

The +utf8Title X resource setting tells xterm to +disable a reconversion of the title string back to +ISO-8859-1, allowing the title strings to be interpreted as +UTF-8. The same feature can be enabled using the title mode +control sequence described in this summary.

+ +

Separate from the +ability to set the titles, xterm provides the ability +to query the titles, returning them either in ISO-8859-1 or +UTF-8. This choice is available only while xterm is +using UTF-8 encoding.

+ +

Finally, the +characters sent to, or returned by a title control are less +constrained than the rest of the control sequences. To make +them more manageable (and constrained), for use in shell +scripts, xterm has an optional feature which decodes +the string from hexadecimal (for setting titles) or for +encoding the title into hexadecimal when querying the +value.

+ + +

Mouse Tracking

+ + +

The VT widget can +be set to send the mouse position and other information on +button presses. These modes are typically used by editors +and other full-screen applications that want to make use of +the mouse.

+ +

There are two sets +of mutually exclusive modes:

+ + + + + + + + + + + + +
+ + +

+ + +

mouse protocol

+
+ + +

+ + +

protocol encoding

+
+ +

The mouse protocols +include DEC Locator mode, enabled by the DECELR +CSI P s +; P s ’ z control sequence, and +is not described here (control sequences are summarized +above). The remaining five modes of the mouse protocols are +each enabled (or disabled) by a different parameter in the +"DECSET CSI ? P +m h " or "DECRST +CSI ? P +m l " control sequence.

+ +

Manifest constants +for the parameter values are defined in xcharmouse.h +as follows:

+ +

#define +SET_X10_MOUSE 9
+#define SET_VT200_MOUSE 1000
+#define SET_VT200_HIGHLIGHT_MOUSE 1001
+#define SET_BTN_EVENT_MOUSE 1002
+#define SET_ANY_EVENT_MOUSE 1003

+ +

#define +SET_FOCUS_EVENT_MOUSE 1004

+ +

#define +SET_EXT_MODE_MOUSE 1005
+#define SET_SGR_EXT_MODE_MOUSE 1006
+#define SET_URXVT_EXT_MODE_MOUSE 1015

+ +

The motion +reporting modes are strictly xterm extensions, and +are not part of any standard, though they are analogous to +the DEC VT200 DECELR locator reports.

+ +

Normally, +parameters (such as pointer position and button number) for +all mouse tracking escape sequences generated by +xterm encode numeric parameters in a single character +as value+32. For example, ! specifies the value 1. +The upper left character position on the terminal is denoted +as 1,1. This scheme dates back to X10, though the normal +mouse-tracking (from X11) is more elaborate.

+ +

X10 compatibility +mode sends an escape sequence only on button press, encoding +the location and the mouse button pressed. It is enabled by +specifying parameter 9 to DECSET. On button press, +xterm sends CSI M C +b C x C y +(6 characters).

+ + + + + + + + + + +
+ + +

+ + +

C b is +button−1.

+ + +

+ + +

C x and C +y are the x and y coordinates of the +mouse when the button was pressed.

+ +

Normal tracking +mode sends an escape sequence on both button press and +release. Modifier key (shift, ctrl, meta) information is +also sent. It is enabled by specifying parameter 1000 to +DECSET. On button press or release, xterm sends +CSI M C b C +x C y .

+ + + + + + + + + + + + + + +
+ + +

+ + +

The low two bits of C +b encode button information: 0=MB1 +pressed, 1=MB2 pressed, 2=MB3 pressed, 3=release.

+ + +

+ + +

The next three bits encode the modifiers +which were down when the button was pressed and are added +together: 4=Shift, 8=Meta, 16=Control. Note however that the +shift and control bits are normally unavailable because +xterm uses the control modifier with mouse for popup +menus, and the shift modifier is used in the default +translations for button events. The Meta modifier +recognized by xterm is the mod1 mask, and is +not necessarily the "Meta" key (see +xmodmap).

+ + +

+ + +

C x and C +y are the x and y coordinates of the +mouse event, encoded as in X10 mode.

+ +

Wheel mice may +return buttons 4 and 5. Those buttons are represented by the +same event codes as buttons 1 and 2 respectively, except +that 64 is added to the event code. Release events for the +wheel buttons are not reported.

+ +

Mouse highlight +tracking notifies a program of a button press, receives a +range of lines from the program, highlights the region +covered by the mouse within that range until button release, +and then sends the program the release coordinates. It is +enabled by specifying parameter 1001 to DECSET. Highlighting +is performed only for button 1, though other button events +can be received.

+ +

Warning: use +of this mode requires a cooperating program or it will hang +xterm.

+ +

On button press, +the same information as for normal tracking is generated; +xterm then waits for the program to send mouse +tracking information. All X events are ignored until the +proper escape sequence is received from the pty: +CSI P s +; P s ; P s ; +P s ; P s T . +The parameters are func, startx, starty, firstrow, +and lastrow. func is non-zero to initiate highlight +tracking and zero to abort. startx and starty +give the starting x and y location for the highlighted +region. The ending location tracks the mouse, but will never +be above row firstrow and will always be above row +lastrow. (The top of the screen is row 1.) When the +button is released, xterm reports the ending position +one of two ways:

+ + + + + + + +
+ + +

+ + +

if the start and end coordinates are the +same locations:

+
+ + +

CSI +t C x C y .

+ + + + + + + +
+ + +

+ + +

otherwise:

+
+ + +

CSI +T C x C y C +x C y C x C +y .
+The parameters are startx, starty, endx, endy, +mousex, and mousey.

+ + + + + + + + + + + + +
+ + +

+ + +

startx, starty, endx, and +endy give the starting and ending character positions +of the region.

+ + +

+ + +

mousex and mousey give the +location of the mouse at button up, which may not be over a +character.

+ +

Button-event +tracking is essentially the same as normal tracking, but +xterm also reports button-motion events. Motion +events are reported only if the mouse pointer has moved to a +different character cell. It is enabled by specifying +parameter 1002 to DECSET. On button press or release, +xterm sends the same codes used by normal tracking +mode.

+ + + + + + + + + + +
+ + +

+ + +

On button-motion events, xterm adds +32 to the event code (the third character, C +b ).

+ + +

+ + +

The other bits of the event code specify +button and modifier keys as in normal mode. For example, +motion into cell x,y with button 1 down is reported as +CSI M @ C x +C y . ( @ = 32 + 0 (button 1) + 32 +(motion indicator) ). Similarly, motion with button 3 +down is reported as CSI M B +C x C y . ( B = 32 ++ 2 (button 3) + 32 (motion indicator) ).

+ +

Any-event mode is +the same as button-event mode, except that all motion events +are reported, even if no mouse button is down. It is enabled +by specifying 1003 to DECSET.

+ +

FocusIn/FocusOut +can be combined with any of the mouse events since it uses a +different protocol. When set, it causes xterm to send +CSI I when the terminal gains +focus, and CSI O when it loses +focus.

+ +

The original X10 +mouse protocol limits the C x and C +y ordinates to 223 (=255 - 32). +Xterm supports more than one scheme for extending +this range, by changing the protocol encoding:

+ + + + + +
+ + +

UTF-8 (1005)

+
+ +

This enables UTF-8 encoding for +C x and C y +under all tracking modes, expanding the maximum encodable +position from 223 to 2015. For positions less than 95, the +resulting output is identical under both modes. Under +extended mouse mode, positions greater than 95 generate +"extra" bytes which will confuse applications +which do not treat their input as a UTF-8 stream. Likewise, +C b will be UTF-8 encoded, to reduce +confusion with wheel mouse events.
+Under normal mouse mode, positions outside (160,94) result +in byte pairs which can be interpreted as a single UTF-8 +character; applications which do treat their input as UTF-8 +will almost certainly be confused unless extended mouse mode +is active.
+This scheme has the drawback that the encoded coordinates +will not pass through luit unchanged, e.g., for +locales using non-UTF-8 encoding.

+ + + + + +
+ + +

SGR (1006)

+ + +

The normal mouse response is altered to use +CSI < followed by +semicolon-separated encoded button value, the C +x and C y ordinates +and a final character which is M for button press and m for +button release.

+ +

The encoded button value in +this case does not add 32 since that was useful only in the +X10 scheme for ensuring that the byte containing the button +value is a printable code. The modifiers are encoded in the +same way. A different final character is used for button +release to resolve the X10 ambiguity regarding which button +was released.
+The highlight tracking responses are also modified to an +SGR-like format, using the same SGR-style scheme and +button-encodings.

+ + + + + +
+ + +

URXVT (1015)

+
+ +

The normal mouse response is +altered to use CSI followed by +semicolon-separated encoded button value, the C +x and C y ordinates +and final character M .
+This uses the same button encoding as X10, but printing it +as a decimal integer rather than as a single byte.
+However, CSI M can be mistaken +for DL (delete lines), while the highlight tracking +CSI T can be mistaken for SD +(scroll down), and the Window manipulation controls. For +these reasons, the 1015 control is not recommended; it is +not an improvement over 1005.

+ + +

Tektronix 4014 Mode

+ + +

Most of these +sequences are standard Tektronix 4014 control sequences. +Graph mode supports the 12-bit addressing of the Tektronix +4014. The major features missing are the write-through and +defocused modes. This document does not describe the +commands used in the various Tektronix plotting modes but +does describe the commands to switch modes.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +

BEL

+ + +

Bell (Ctrl-G).

+ + +

BS

+ + +

Backspace (Ctrl-H).

+ + +

TAB

+ + +

Horizontal Tab (Ctrl-I).

+ + +

LF

+ + +

Line Feed or New Line (Ctrl-J).

+ + +

VT

+ + +

Cursor up (Ctrl-K).

+ + +

FF

+ + +

Form Feed or New Page (Ctrl-L).

+ + +

CR

+ + +

Carriage Return (Ctrl-M).

+ + +

ESC ETX

+ + +

Switch to VT100 Mode ( +ESC Ctrl-C).

+ + +

ESC ENQ

+ + +

Return Terminal Status ( +ESC Ctrl-E).

+ + +

ESC FF

+ + +

PAGE (Clear Screen) ( +ESC Ctrl-L).

+ + +

ESC SO

+ + +

Begin 4015 APL mode ( +ESC Ctrl-N). (This is ignored +by xterm).

+ + +

ESC SI

+ + +

End 4015 APL mode ( +ESC Ctrl-O). (This is ignored +by xterm).

+ + +

ESC ETB

+ + +

COPY (Save Tektronix Codes to file +COPYyyyy-mm-dd.hh:mm:ss).

+ + +

ETB +(end transmission block) is the same as Ctrl-W.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +

ESC CAN

+ + +

Bypass Condition ( +ESC Ctrl-X).

+
+ + +

ESC SUB

+ + +

GIN mode ( +ESC Ctrl-Z).

+
+ + +

ESC FS

+ + +

Special Point Plot Mode ( +ESC Ctrl-\).

+
+ + +

ESC 8

+ + +

Select Large Character Set.

+
+ + +

ESC 9

+ + +

Select #2 Character Set.

+
+ + +

ESC :

+ + +

Select #3 Character Set.

+
+ + +

ESC ;

+ + +

Select Small Character Set.

+
+ + +

OSC P +s ; P

+
+ +

t +BEL

+ + + + + + +
+ + +

Set Text Parameters of VT window.

+
+ +

P s = 0 +→ Change Icon Name and Window Title to P +t .
+P s
= 1 → Change Icon Name to P +t .
+P s
= 2 → Change Window Title to +P t .
+P s
= 4 6 → Change Log File to P +t . (This is normally disabled by a +compile-time option).

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +

ESC `

+ + +

Normal Z Axis and Normal (solid) +Vectors.

+
+ + +

ESC a

+ + +

Normal Z Axis and Dotted Line Vectors.

+
+ + +

ESC b

+ + +

Normal Z Axis and Dot-Dashed Vectors.

+
+ + +

ESC c

+ + +

Normal Z Axis and Short-Dashed Vectors.

+
+ + +

ESC d

+ + +

Normal Z Axis and Long-Dashed Vectors.

+
+ + +

ESC h

+ + +

Defocused Z Axis and Normal (solid) +Vectors.

+
+ + +

ESC i

+ + +

Defocused Z Axis and Dotted Line +Vectors.

+
+ + +

ESC j

+ + +

Defocused Z Axis and Dot-Dashed +Vectors.

+
+ + +

ESC k

+ + +

Defocused Z Axis and Short-Dashed +Vectors.

+
+ + +

ESC l

+ + +

Defocused Z Axis and Long-Dashed +Vectors.

+
+ + +

ESC p

+ + +

Write-Thru Mode and Normal (solid) +Vectors.

+
+ + +

ESC q

+ + +

Write-Thru Mode and Dotted Line +Vectors.

+
+ + +

ESC r

+ + +

Write-Thru Mode and Dot-Dashed Vectors.

+
+ + +

ESC s

+ + +

Write-Thru Mode and Short-Dashed +Vectors.

+
+ + +

ESC t

+ + +

Write-Thru Mode and Long-Dashed +Vectors.

+
+ + +

FS

+ + +

Point Plot Mode (Ctrl-\).

+
+ + +

GS

+ + +

Graph Mode (Ctrl-]).

+
+ + +

RS

+ + +

Incremental Plot Mode (Ctrl-^).

+
+ + +

US

+ + +

Alpha Mode (Ctrl-_).

+
+ + +

VT52 Mode

+ + +

Parameters for +cursor movement are at the end of the +ESC Y escape sequence. Each +ordinate is encoded in a single character as +value+32. For example, ! is 1. The screen coordinate +system is 0-based.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +

ESC +A

+ + +

Cursor up.

+
+ + +

ESC B

+ + +

Cursor down.

+
+ + +

ESC C

+ + +

Cursor right.

+
+ + +

ESC D

+ + +

Cursor left.

+
+ + +

ESC F

+ + +

Enter graphics mode.

+
+ + +

ESC G

+ + +

Exit graphics mode.

+
+ + +

ESC H

+ + +

Move the cursor to the home position.

+
+ + +

ESC I

+ + +

Reverse line feed.

+
+ + +

ESC J

+ + +

Erase from the cursor to the end of the +screen.

+
+ + +

ESC K

+ + +

Erase from the cursor to the end of the +line.

+
+ + +

ESC Y P +s P

+
+ +

s

+ + + + + + + + + + + + +
+ + +

Move the cursor to given row and +column.

+
+ + +

ESC Z

+ + +

Identify.

+
+ +

→ +ESC / Z (‘‘I am a +VT52.’’).

+ + + + + + + + + + + + + + + + + +
+ + +

ESC =

+ + +

Enter alternate keypad mode.

+
+ + +

ESC >

+ + +

Exit alternate keypad mode.

+
+ + +

ESC <

+ + +

Exit VT52 mode (Enter VT100 mode).

+
+
+ + diff --git a/yat/tests/auto/auto.pro b/yat/tests/auto/auto.pro new file mode 100644 index 0000000..970400f --- /dev/null +++ b/yat/tests/auto/auto.pro @@ -0,0 +1,3 @@ +TEMPLATE = subdirs +SUBDIRS = \ + line diff --git a/yat/tests/auto/line/line.pro b/yat/tests/auto/line/line.pro new file mode 100644 index 0000000..9b4c7b2 --- /dev/null +++ b/yat/tests/auto/line/line.pro @@ -0,0 +1,8 @@ +CONFIG += testcase +QT += testlib quick + +include(../../../backend/backend.pri) + +SOURCES += \ + tst_line.cpp \ + diff --git a/yat/tests/auto/line/tst_line.cpp b/yat/tests/auto/line/tst_line.cpp new file mode 100644 index 0000000..1c3e4b8 --- /dev/null +++ b/yat/tests/auto/line/tst_line.cpp @@ -0,0 +1,724 @@ +#include "../../../backend/line.h" +#include + +#include +#include "../../../backend/screen.h" + +class LineHandler +{ +public: + LineHandler() { + screen.setHeight(50); + screen.setWidth(100); + screen.line_at_cursor()->clear(); + QCOMPARE(line()->style_list().size(), 1); + default_style = line()->style_list().at(0); + default_text_style = default_style.style; + } + + Line *line() const + { + return screen.line_at_cursor(); + } + + TextStyle default_style; + TextStyle::Styles default_text_style; + Screen screen; +}; + +class tst_Line: public QObject +{ + Q_OBJECT + +private slots: + void replaceStart(); + void replaceEdgeOfStyle(); + void replaceCompatibleStyle(); + void replaceIncompatibleStyle(); + void replaceIncompaitibleStylesCrossesBoundary(); + void replace3IncompatibleStyles(); + void replaceIncomaptibleStylesCrosses2Boundaries(); + void replaceSwapStyles(); + void replaceEndLine(); + void clearLine(); + void clearToEndOfLine1Segment(); + void clearToEndOfLine3Segment(); + void clearToEndOfLineMiddle3Segment(); + void deleteCharacters1Segment(); + void deleteCharacters2Segments(); + void deleteCharacters3Segments(); + void deleteCharactersRemoveSegmentEnd(); + void deleteCharactersRemoveSegmentBeginning(); + void insertCharacters(); + void insertCharacters2Segments(); + void insertCharacters3Segments(); +}; + +void tst_Line::replaceStart() +{ + LineHandler lineHandler; + Line *line = lineHandler.line(); + + QVector old_style_list = line->style_list(); + QCOMPARE(old_style_list.size(), 1); + + QString replace_text("This is a test"); + TextStyle textStyle; + textStyle.style = TextStyle::Overlined; + line->replaceAtPos(0,replace_text, textStyle); + + QVector new_style_list = line->style_list(); + TextStyleLine first_style = new_style_list.at(0); + QCOMPARE(first_style.start_index, 0); + QCOMPARE(first_style.end_index, replace_text.size() - 1); + QCOMPARE(new_style_list.size(), 2); + +} + +void tst_Line::replaceEdgeOfStyle() +{ + LineHandler lineHandler; + Line *line = lineHandler.line(); + + QString first_text("This is the First"); + TextStyle textStyle; + textStyle.style = TextStyle::Overlined; + line->replaceAtPos(0,first_text, textStyle); + + QString second_text("This is the Second"); + textStyle.style = TextStyle::Bold; + line->replaceAtPos(first_text.size(), second_text, textStyle); + + QVector style_list = line->style_list(); + + QCOMPARE(style_list.size(), 3); + + const TextStyleLine &first_style = style_list.at(0); + QCOMPARE(first_style.style, TextStyle::Overlined); + QCOMPARE(first_style.start_index, 0); + QCOMPARE(first_style.end_index, first_text.size() - 1); + + const TextStyleLine &second_style = style_list.at(1); + QCOMPARE(second_style.style, TextStyle::Bold); + QCOMPARE(second_style.start_index, first_text.size()); + QCOMPARE(second_style.end_index, first_text.size()+ second_text.size() - 1); + + const TextStyleLine &third_style = style_list.at(2); + QCOMPARE(third_style.style, TextStyle::Normal); + QCOMPARE(third_style.start_index, first_text.size()+ second_text.size()); +} + +void tst_Line::replaceCompatibleStyle() +{ + LineHandler lineHandler; + Line *line = lineHandler.line(); + + QString replace_text("replaceed Text"); + line->replaceAtPos(10, replace_text, lineHandler.default_style); + + QVector after_style_list = line->style_list(); + QCOMPARE(after_style_list.size(), 1); + QCOMPARE(after_style_list.at(0).style, lineHandler.default_text_style); +} + +void tst_Line::replaceIncompatibleStyle() +{ + LineHandler lineHandler; + Line *line = lineHandler.line(); + + + QString replace_text("replaceed Text"); + TextStyle replace_style; + replace_style.style = TextStyle::Blinking; + line->replaceAtPos(10, replace_text, replace_style); + + QVector after_style_list = line->style_list(); + QCOMPARE(after_style_list.size(), 3); + + const TextStyleLine &first_style = after_style_list.at(0); + QCOMPARE(first_style.start_index, 0); + QCOMPARE(first_style.end_index, 9); + QCOMPARE(first_style.style, lineHandler.default_text_style); + + const TextStyleLine &second_style = after_style_list.at(1); + QCOMPARE(second_style.start_index, 10); + QCOMPARE(second_style.end_index, 10 + replace_text.size() -1); + QCOMPARE(second_style.style, TextStyle::Blinking); + + const TextStyleLine &third_style = after_style_list.at(2); + QCOMPARE(third_style.start_index, 10 + replace_text.size()); + QCOMPARE(third_style.style, lineHandler.default_text_style); +} + +void tst_Line::replaceIncompaitibleStylesCrossesBoundary() +{ + LineHandler lineHandler; + Line *line = lineHandler.line(); + + QString replace_text("replaceed Text"); + TextStyle replace_style; + replace_style.style = TextStyle::Blinking; + line->replaceAtPos(0, replace_text, replace_style); + + QString crosses_boundary("New incompatible text"); + replace_style.style = TextStyle::Framed; + int replace_pos = replace_text.size()/2; + line->replaceAtPos(replace_pos, crosses_boundary, replace_style); + + QVector after_style_list = line->style_list(); + QCOMPARE(after_style_list.size(), 3); + + const TextStyleLine &first_style = after_style_list.at(0); + QCOMPARE(first_style.start_index, 0); + QCOMPARE(first_style.end_index, replace_pos -1); + QCOMPARE(first_style.style, TextStyle::Blinking); + + const TextStyleLine &second_style = after_style_list.at(1); + QCOMPARE(second_style.start_index, replace_pos); + QCOMPARE(second_style.end_index, replace_pos + crosses_boundary.size() -1); + QCOMPARE(second_style.style, TextStyle::Framed); + + const TextStyleLine &third_style = after_style_list.at(2); + QCOMPARE(third_style.start_index, replace_pos + crosses_boundary.size()); + QCOMPARE(third_style.style, lineHandler.default_text_style); +} + +void tst_Line::replace3IncompatibleStyles() +{ + LineHandler lineHandler; + Line *line = lineHandler.line(); + + QString first_text("First Text"); + TextStyle replace_style; + replace_style.style = TextStyle::Blinking; + line->replaceAtPos(0, first_text, replace_style); + + QString second_text("Second Text"); + replace_style.style = TextStyle::Italic; + line->replaceAtPos(first_text.size(), second_text, replace_style); + + QString third_text("Third Text"); + replace_style.style = TextStyle::Encircled; + line->replaceAtPos(first_text.size() + second_text.size(), third_text, replace_style); + + QCOMPARE(line->style_list().size(), 4); + + QVector after_style_list = line->style_list(); + + const TextStyleLine &first_style = after_style_list.at(0); + QCOMPARE(first_style.start_index, 0); + QCOMPARE(first_style.end_index, first_text.size() -1); + + const TextStyleLine &second_style = after_style_list.at(1); + QCOMPARE(second_style.start_index, first_text.size()); + QCOMPARE(second_style.end_index, first_text.size() + second_text.size() - 1); + QCOMPARE(second_style.style, TextStyle::Italic); + + const TextStyleLine &third_style = after_style_list.at(2); + QCOMPARE(third_style.start_index, first_text.size() + second_text.size()); + QCOMPARE(third_style.end_index, first_text.size() + second_text.size() + third_text.size() - 1); + QCOMPARE(third_style.style, TextStyle::Encircled); + + const TextStyleLine &fourth_style = after_style_list.at(3); + QCOMPARE(fourth_style.start_index, first_text.size() + second_text.size() + third_text.size()); +} +void tst_Line::replaceIncomaptibleStylesCrosses2Boundaries() +{ + LineHandler lineHandler; + Line *line = lineHandler.line(); + + QString first_text("First Text"); + TextStyle replace_style; + replace_style.style = TextStyle::Blinking; + line->replaceAtPos(0, first_text, replace_style); + + QString second_text("Second Text"); + replace_style.style = TextStyle::Italic; + line->replaceAtPos(first_text.size(), second_text, replace_style); + + QString third_text("Third Text"); + replace_style.style = TextStyle::Encircled; + line->replaceAtPos(first_text.size() + second_text.size(), third_text, replace_style); + + QCOMPARE(line->style_list().size(), 4); + + QVector before_style_list = line->style_list(); + + QString overlap_first_third; + overlap_first_third.fill(QChar('A'), second_text.size() + 4); + replace_style.style = TextStyle::DoubleUnderlined; + line->replaceAtPos(first_text.size() -2, overlap_first_third, replace_style); + + QVector after_style_list = line->style_list(); + QCOMPARE(line->style_list().size(), 4); + + const TextStyleLine &first_style = after_style_list.at(0); + QCOMPARE(first_style.start_index, 0); + QCOMPARE(first_style.end_index, first_text.size() - 3); + QCOMPARE(first_style.style, TextStyle::Blinking); + + const TextStyleLine &second_style = after_style_list.at(1); + QCOMPARE(second_style.style, TextStyle::DoubleUnderlined); + QCOMPARE(second_style.start_index, first_text.size() - 2); + QCOMPARE(second_style.end_index, first_text.size() - 2 + overlap_first_third.size() -1); + + const TextStyleLine &third_style = after_style_list.at(2); + QCOMPARE(third_style.style, TextStyle::Encircled); + QCOMPARE(third_style.start_index, first_text.size() - 2 + overlap_first_third.size()); + QCOMPARE(third_style.end_index, first_text.size() - 2 + overlap_first_third.size() + third_text.size() - 1 - 2); + + const TextStyleLine &fourth_style = after_style_list.at(3); + QCOMPARE(fourth_style.style, lineHandler.default_text_style); + QCOMPARE(fourth_style.start_index, first_text.size() - 2 + overlap_first_third.size() + third_text.size() - 2); +} + +void tst_Line::replaceSwapStyles() +{ + LineHandler lineHandler; + Line *line = lineHandler.line(); + + QString first_text("First Text"); + TextStyle replace_style; + replace_style.style = TextStyle::Blinking; + line->replaceAtPos(0, first_text, replace_style); + + QString second_text("Second Text"); + replace_style.style = TextStyle::Italic; + line->replaceAtPos(first_text.size(), second_text, replace_style); + + QString third_text("Third Text"); + replace_style.style = TextStyle::Encircled; + line->replaceAtPos(first_text.size() + second_text.size(), third_text, replace_style); + + QString replace_second("Dnoces Text"); + replace_style.style = TextStyle::Bold; + line->replaceAtPos(first_text.size(), replace_second, replace_style); + + QCOMPARE(line->style_list().size(), 4); +} + +void tst_Line::replaceEndLine() +{ + LineHandler lineHandler; + Line *line = lineHandler.line(); + + QString *full_line = line->textLine(); + int line_size = full_line->size(); + + QString replace_text("at the end of the string"); + TextStyle style = lineHandler.default_style; + style.style = TextStyle::Bold; + line->replaceAtPos(line_size - replace_text.size(), replace_text, style); + + QCOMPARE(line->textLine()->size(), line_size); + + QVector style_list = line->style_list(); + QCOMPARE(style_list.size(), 2); + + const TextStyleLine &first_style = style_list.at(0); + QCOMPARE(first_style.start_index, 0); + QCOMPARE(first_style.end_index, line_size - replace_text.size() -1); + QCOMPARE(first_style.style, lineHandler.default_text_style); + + const TextStyleLine &second_style = style_list.at(1); + QCOMPARE(second_style.start_index, line_size - replace_text.size()); + QCOMPARE(second_style.end_index, line_size - 1); + QCOMPARE(second_style.style, TextStyle::Bold); +} + +void tst_Line::clearLine() +{ + LineHandler lineHandler; + Line *line = lineHandler.line(); + + QVERIFY(line->textLine()->size() > 0); + QCOMPARE(line->textLine()->trimmed().size(), 0); +} + +void tst_Line::clearToEndOfLine1Segment() +{ + LineHandler lineHandler; + Line *line = lineHandler.line(); + + QString replace_text("To be replaceed"); + TextStyle style = lineHandler.default_style; + style.style = TextStyle::Encircled; + line->replaceAtPos(0, replace_text, style); + + int before_clear_size = line->textLine()->size(); + line->clearToEndOfLine(5); + + int after_clear_size = line->textLine()->size(); + QCOMPARE(after_clear_size, before_clear_size); + QVector style_list = line->style_list(); + QCOMPARE(style_list.size(), 2); + + const TextStyleLine &first_style = style_list.at(0); + QCOMPARE(first_style.start_index, 0); + QCOMPARE(first_style.end_index, 4); + + const TextStyleLine &second_style = style_list.at(1); + QCOMPARE(second_style.start_index, 5); + + QString cleared("To be"); + QCOMPARE(line->textLine()->trimmed(), cleared); +} + +void tst_Line::clearToEndOfLine3Segment() +{ + LineHandler lineHandler; + Line *line = lineHandler.line(); + + QString replace_text("To be"); + TextStyle style = lineHandler.default_style; + style.style = TextStyle::Encircled; + line->replaceAtPos(0, replace_text, style); + + QString replace_text2(" or not to be"); + style.style = TextStyle::Bold; + line ->replaceAtPos(replace_text.size(), replace_text2, style); + + line->clearToEndOfLine(replace_text.size()); + + QVector style_list = line->style_list(); + QCOMPARE(style_list.size(), 2); + + const TextStyleLine &first_style = style_list.at(0); + QCOMPARE(first_style.start_index, 0); + QCOMPARE(first_style.end_index, replace_text.size() - 1); + + const TextStyleLine &second_style = style_list.at(1); + QCOMPARE(second_style.start_index, replace_text.size()); + QCOMPARE(second_style.style, lineHandler.default_text_style); +} + +void tst_Line::clearToEndOfLineMiddle3Segment() +{ + LineHandler lineHandler; + Line *line = lineHandler.line(); + + QString replace_text("To be"); + TextStyle style = lineHandler.default_style; + style.style = TextStyle::Encircled; + line->replaceAtPos(0, replace_text, style); + + QString replace_text2(" or not to be"); + style.style = TextStyle::Bold; + line ->replaceAtPos(replace_text.size(), replace_text2, style); + + line->clearToEndOfLine(replace_text.size() + 3); + + QVector style_list = line->style_list(); + QCOMPARE(style_list.size(), 3); + + const TextStyleLine &first_style = style_list.at(0); + QCOMPARE(first_style.start_index, 0); + QCOMPARE(first_style.end_index, replace_text.size() - 1); + + const TextStyleLine &second_style = style_list.at(1); + QCOMPARE(second_style.start_index, replace_text.size()); + QCOMPARE(second_style.end_index, replace_text.size() + 2); + + const TextStyleLine &third_style = style_list.at(2); + QCOMPARE(third_style.start_index, replace_text.size() + 3); + QCOMPARE(third_style.style, lineHandler.default_text_style); +} + +void tst_Line::deleteCharacters1Segment() +{ + LineHandler lineHandler; + Line *line = lineHandler.line(); + + QString replace_text("replaceing some text"); + TextStyle style = lineHandler.default_style; + style.style = TextStyle::Encircled; + line->replaceAtPos(0, replace_text, style); + + QString *full_line = line->textLine(); + int line_size = full_line->size(); + + line->deleteCharacters(10,14); + + QCOMPARE(line->textLine()->size(), line_size); + + QVector style_list = line->style_list(); + QCOMPARE(style_list.size(), 2); + + const TextStyleLine &first_style = style_list.at(0); + QCOMPARE(first_style.start_index, 0); + QCOMPARE(first_style.end_index, 14); + + const TextStyleLine &second_style = style_list.at(1); + QCOMPARE(second_style.start_index, 15); + QCOMPARE(second_style.style, lineHandler.default_text_style); +} + +void tst_Line::deleteCharacters2Segments() +{ + LineHandler lineHandler; + Line *line = lineHandler.line(); + + QString replace_text("replaceing some text"); + TextStyle style = lineHandler.default_style; + style.style = TextStyle::Encircled; + line->replaceAtPos(0, replace_text, style); + + QString *full_line = line->textLine(); + int line_size = full_line->size(); + + line->deleteCharacters(15,25); + + QCOMPARE(line->textLine()->size(), line_size); + + QVector style_list = line->style_list(); + QCOMPARE(style_list.size(), 2); + + const TextStyleLine &first_style = style_list.at(0); + QCOMPARE(first_style.start_index, 0); + QCOMPARE(first_style.end_index, 14); + + const TextStyleLine &second_style = style_list.at(1); + QCOMPARE(second_style.start_index, 15); + QCOMPARE(second_style.style, lineHandler.default_text_style); + +} + +void tst_Line::deleteCharacters3Segments() +{ + LineHandler lineHandler; + Line *line = lineHandler.line(); + + QString replace_text("replaceing some text"); + TextStyle style = lineHandler.default_style; + style.style = TextStyle::Encircled; + line->replaceAtPos(0, replace_text, style); + + QString replace_more_text("Some more text"); + style.style = TextStyle::Bold; + line->replaceAtPos(replace_text.size(), replace_more_text, style); + + QString *full_line = line->textLine(); + int line_size = full_line->size(); + + line->deleteCharacters(10,15); + + QCOMPARE(line->textLine()->size(), line_size); + + QVector style_list = line->style_list(); + QCOMPARE(style_list.size(), 3); + + const TextStyleLine &first_style = style_list.at(0); + QCOMPARE(first_style.start_index, 0); + QCOMPARE(first_style.end_index, 13); + + const TextStyleLine &second_style = style_list.at(1); + QCOMPARE(second_style.start_index, 14); + QCOMPARE(second_style.end_index, 14 + replace_more_text.size() -1); + QCOMPARE(second_style.style, TextStyle::Bold); + + const TextStyleLine &third_style = style_list.at(2); + QCOMPARE(third_style.start_index, 14 + replace_more_text.size()); + QCOMPARE(third_style.style, lineHandler.default_text_style); +} + +void tst_Line::deleteCharactersRemoveSegmentEnd() +{ + LineHandler lineHandler; + Line *line = lineHandler.line(); + + QString replace_text("replaceing some text"); + TextStyle style = lineHandler.default_style; + style.style = TextStyle::Encircled; + line->replaceAtPos(0, replace_text, style); + + QString replace_more_text("Some more text"); + style.style = TextStyle::Bold; + line->replaceAtPos(replace_text.size(), replace_more_text, style); + + QString *full_line = line->textLine(); + int line_size = full_line->size(); + + line->deleteCharacters(16,33); + + QCOMPARE(line->textLine()->size(), line_size); + + QVector style_list = line->style_list(); + QCOMPARE(style_list.size(), 2); + + const TextStyleLine &first_style = style_list.at(0); + QCOMPARE(first_style.start_index, 0); + QCOMPARE(first_style.end_index, 15); + + const TextStyleLine &second_style = style_list.at(1); + QCOMPARE(second_style.start_index, 16); + QCOMPARE(second_style.style, lineHandler.default_text_style); + +} + +void tst_Line::deleteCharactersRemoveSegmentBeginning() +{ + LineHandler lineHandler; + Line *line = lineHandler.line(); + + QString replace_text("replaceing some text"); + TextStyle style = lineHandler.default_style; + style.style = TextStyle::Encircled; + line->replaceAtPos(0, replace_text, style); + + QString replace_more_text("Some more text"); + style.style = TextStyle::Bold; + line->replaceAtPos(replace_text.size(), replace_more_text, style); + + QString *full_line = line->textLine(); + int line_size = full_line->size(); + + line->deleteCharacters(replace_text.size(),replace_text.size() + replace_more_text.size() + 3); + + QCOMPARE(line->textLine()->size(), line_size); + + QVector style_list = line->style_list(); + QCOMPARE(style_list.size(), 2); + + const TextStyleLine &first_style = style_list.at(0); + QCOMPARE(first_style.start_index, 0); + QCOMPARE(first_style.end_index, replace_text.size() - 1); + + const TextStyleLine &second_style = style_list.at(1); + QCOMPARE(second_style.start_index, replace_text.size()); + QCOMPARE(second_style.style, lineHandler.default_text_style); +} + +void tst_Line::insertCharacters() +{ + LineHandler lineHandler; + Line *line = lineHandler.line(); + + QString *full_line = line->textLine(); + int line_size = full_line->size(); + + QString insert_text("inserting some text"); + TextStyle style = lineHandler.default_style; + style.style = TextStyle::Encircled; + line->insertAtPos(5, insert_text, style); + + QCOMPARE(line->textLine()->size(), line_size); + + QVector style_list = line->style_list(); + QCOMPARE(style_list.size(), 3); + + const TextStyleLine &first_style = style_list.at(0); + QCOMPARE(first_style.start_index, 0); + QCOMPARE(first_style.end_index, 4); + QCOMPARE(first_style.style, lineHandler.default_text_style); + + const TextStyleLine &second_style = style_list.at(1); + QCOMPARE(second_style.start_index, 5); + QCOMPARE(second_style.end_index, 5 + insert_text.size() -1); + QCOMPARE(second_style.style, TextStyle::Encircled); + + const TextStyleLine &third_style = style_list.at(2); + QCOMPARE(third_style.start_index, 5 + insert_text.size()); + QCOMPARE(third_style.end_index, line_size - 1); + QCOMPARE(third_style.style, lineHandler.default_text_style); +} + +void tst_Line::insertCharacters2Segments() +{ + LineHandler lineHandler; + Line *line = lineHandler.line(); + + QString *full_line = line->textLine(); + int line_size = full_line->size(); + + QString replace_text("at the end of the string"); + TextStyle style = lineHandler.default_style; + style.style = TextStyle::Bold; + line->replaceAtPos(line_size - replace_text.size(), replace_text, style); + + QString insert_text("inserting some text"); + style.style = TextStyle::Encircled; + line->insertAtPos(5, insert_text, style); + + QCOMPARE(line->textLine()->size(), line_size); + + QVector style_list = line->style_list(); + QCOMPARE(style_list.size(), 4); + + const TextStyleLine &first_style = style_list.at(0); + QCOMPARE(first_style.start_index, 0); + QCOMPARE(first_style.end_index, 4); + QCOMPARE(first_style.style, lineHandler.default_text_style); + + const TextStyleLine &second_style = style_list.at(1); + QCOMPARE(second_style.start_index, 5); + QCOMPARE(second_style.end_index, 5 + insert_text.size() -1); + QCOMPARE(second_style.style, TextStyle::Encircled); + + const TextStyleLine &third_style = style_list.at(2); + QCOMPARE(third_style.start_index, 5 + insert_text.size()); + QCOMPARE(third_style.end_index, line_size -1 - replace_text.size() + insert_text.size()); + QCOMPARE(third_style.style, lineHandler.default_text_style); + + const TextStyleLine &fourth_style = style_list.at(3); + QCOMPARE(fourth_style.start_index, line_size - replace_text.size() + insert_text.size()); + QCOMPARE(fourth_style.end_index, line_size -1 ); + QCOMPARE(fourth_style.style, TextStyle::Bold); +} + +void tst_Line::insertCharacters3Segments() +{ + LineHandler lineHandler; + Line *line = lineHandler.line(); + + QString *full_line = line->textLine(); + int line_size = full_line->size(); + + QString replace_text("at the end of the string"); + TextStyle style = lineHandler.default_style; + style.style = TextStyle::Bold; + line->replaceAtPos(line_size - replace_text.size(), replace_text, style); + + QString replace_text2("somewhere in the string"); + style.style = TextStyle::Encircled; + line->replaceAtPos(20,replace_text2, style); + + QVector tmp_style_list = line->style_list(); + QCOMPARE(tmp_style_list.size(), 4); + + QString insert_text("this text is longer than last segment"); + style.style = TextStyle::Italic; + line->insertAtPos(10, insert_text, style); + + QCOMPARE(line->textLine()->size(), line_size); + + QVector style_list = line->style_list(); + QCOMPARE(style_list.size(), 5); + + const TextStyleLine &first_style = style_list.at(0); + QCOMPARE(first_style.start_index, 0); + QCOMPARE(first_style.end_index, 9); + QCOMPARE(first_style.style, lineHandler.default_text_style); + + const TextStyleLine &second_style = style_list.at(1); + QCOMPARE(second_style.start_index, 10); + QCOMPARE(second_style.end_index, 10 + insert_text.size() -1); + QCOMPARE(second_style.style, TextStyle::Italic); + + const TextStyleLine &third_style = style_list.at(2); + QCOMPARE(third_style.start_index, 10 + insert_text.size()); + QCOMPARE(third_style.end_index, 20 + insert_text.size() - 1); + QCOMPARE(third_style.style, lineHandler.default_text_style); + + const TextStyleLine &fourth_style = style_list.at(3); + QCOMPARE(fourth_style.start_index, 20 + insert_text.size()); + QCOMPARE(fourth_style.end_index, 20 + insert_text.size() + replace_text2.size() - 1); + QCOMPARE(fourth_style.style, TextStyle::Encircled); + + const TextStyleLine &fith_style = style_list.at(4); + QCOMPARE(fith_style.start_index, 20 + insert_text.size() + replace_text2.size()); + QCOMPARE(fith_style.end_index, line_size - 1); + QCOMPARE(fith_style.style, lineHandler.default_text_style); +} + +#include +QTEST_MAIN(tst_Line); diff --git a/yat/tests/tests.pro b/yat/tests/tests.pro new file mode 100644 index 0000000..b8445a7 --- /dev/null +++ b/yat/tests/tests.pro @@ -0,0 +1,3 @@ +TEMPLATE = subdirs +SUBDIRS = \ + auto diff --git a/yat/yat.pro b/yat/yat.pro new file mode 100644 index 0000000..fabc7b4 --- /dev/null +++ b/yat/yat.pro @@ -0,0 +1,5 @@ +TEMPLATE=subdirs +CONFIG += ordered +SUBDIRS= \ + yat_declarative \ + tests diff --git a/yat/yat_declarative/main.cpp b/yat/yat_declarative/main.cpp new file mode 100644 index 0000000..e63aec1 --- /dev/null +++ b/yat/yat_declarative/main.cpp @@ -0,0 +1,43 @@ +/************************************************************************************************** +* Copyright (c) 2012 Jørgen Lind +* +* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +* associated documentation files (the "Software"), to deal in the Software without restriction, +* including without limitation the rights to use, copy, modify, merge, publish, distribute, +* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all copies or +* substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT +* NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +* OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +***************************************************************************************************/ + +#include +#include +#include + +#include +#include + +#include "register_qml_types.h" +#include "terminal_screen.h" +#include "yat_pty.h" + +int main(int argc, char **argv) +{ + QGuiApplication app(argc, argv); + + register_qml_types(); + + QQuickView view(QUrl("qrc:/qml/yat_declarative/main.qml")); + + view.setResizeMode(QQuickView::SizeRootObjectToView); + view.show(); + return app.exec(); +} diff --git a/yat/yat_declarative/object_destruct_item.cpp b/yat/yat_declarative/object_destruct_item.cpp new file mode 100644 index 0000000..4f48280 --- /dev/null +++ b/yat/yat_declarative/object_destruct_item.cpp @@ -0,0 +1,55 @@ +/******************************************************************************* +* Copyright (c) 2013 Jørgen Lind +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +*******************************************************************************/ + +#include "object_destruct_item.h" + +ObjectDestructItem::ObjectDestructItem(QQuickItem *parent) + : QQuickItem(parent) + , m_object(0) +{ +} + +QObject *ObjectDestructItem::objectHandle() const +{ + return m_object; +} + +void ObjectDestructItem::setObjectHandle(QObject *object) +{ + bool emit_changed = m_object != object; + if (m_object) { + m_object->disconnect(this); + } + + m_object = object; + connect(m_object, SIGNAL(destroyed()), this, SLOT(objectDestroyed())); + + if (emit_changed) + emit objectHandleChanged(); +} + +void ObjectDestructItem::objectDestroyed() +{ + delete this; +} + diff --git a/yat/yat_declarative/object_destruct_item.h b/yat/yat_declarative/object_destruct_item.h new file mode 100644 index 0000000..fb74691 --- /dev/null +++ b/yat/yat_declarative/object_destruct_item.h @@ -0,0 +1,52 @@ +/******************************************************************************* +* Copyright (c) 2013 Jørgen Lind +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +*******************************************************************************/ + +#ifndef OBJECT_DESTRUCT_ITEM_H +#define OBJECT_DESTRUCT_ITEM_H + +#include +#include + +class ObjectDestructItem : public QQuickItem +{ + Q_OBJECT + + Q_PROPERTY(QObject *objectHandle READ objectHandle WRITE setObjectHandle NOTIFY objectHandleChanged) + +public: + ObjectDestructItem(QQuickItem *parent = 0); + + QObject *objectHandle() const; + void setObjectHandle(QObject *line); + +signals: + void objectHandleChanged(); + +private slots: + void objectDestroyed(); + +private: + QObject *m_object; +}; + +#endif //OBJECT_DESTRUCT_ITEM_H diff --git a/yat/yat_declarative/qml/yat_declarative/HighlightArea.qml b/yat/yat_declarative/qml/yat_declarative/HighlightArea.qml new file mode 100644 index 0000000..bc40a1c --- /dev/null +++ b/yat/yat_declarative/qml/yat_declarative/HighlightArea.qml @@ -0,0 +1,75 @@ +import QtQuick 2.0 + +Item { + id: highlightArea + + property real characterWidth: 0 + property real characterHeight: 0 + property int screenWidth: width / characterWidth + + property point start + property point end + + property color color: "grey" + + width: parent.width + height: parent.height + + opacity: 0.8 + + Rectangle { + id: begginning_rectangle + color: parent.color + opacity: parent.opacity + y:0 + height: characterHeight + } + + Rectangle { + id: middle_rectangle + color: parent.color + opacity: parent.opacity + width: parent.width + x: 0 + anchors.top: begginning_rectangle.bottom + + } + + Rectangle { + id: end_rectangle + color: parent.color + opacity: parent.opacity + x: 0 + height: characterHeight + anchors.top: middle_rectangle.bottom + } + + onCharacterWidthChanged: calculateRectangles(); + onCharacterHeightChanged: calculateRectangles(); + onScreenWidthChanged: calculateRectangles(); + + onStartChanged: calculateRectangles(); + onEndChanged: calculateRectangles(); + + function calculateRectangles() { + highlightArea.y = start.y * characterHeight; + begginning_rectangle.x = start.x * characterWidth; + if (start.y === end.y) { + middle_rectangle.visible = false; + end_rectangle.visible = false + begginning_rectangle.width = (end.x - start.x) * characterWidth; + } else { + begginning_rectangle.width = (screenWidth - start.x) * characterWidth; + if (start.y === end.y - 1) { + middle_rectangle.height = 0; + middle_rectangle.visible = false; + }else { + middle_rectangle.visible = true; + middle_rectangle.height = (end.y - start.y - 1) * characterHeight; + } + end_rectangle.visible = true; + end_rectangle.width = end.x * characterWidth; + } + } + +} diff --git a/yat/yat_declarative/qml/yat_declarative/TerminalLine.qml b/yat/yat_declarative/qml/yat_declarative/TerminalLine.qml new file mode 100644 index 0000000..e1c7ab2 --- /dev/null +++ b/yat/yat_declarative/qml/yat_declarative/TerminalLine.qml @@ -0,0 +1,34 @@ +import QtQuick 2.0 + +import org.yat 1.0 + +ObjectDestructItem { + id: textLine + + property var textComponent : Qt.createComponent("TerminalText.qml") + property font font + property real fontHeight + property real fontWidth + + height: fontHeight + width: parent.width + visible: objectHandle.visible + + Connections { + target: objectHandle + + onIndexChanged: { + y = objectHandle.index * fontHeight; + } + + onTextCreated: { + var textSegment = textComponent.createObject(textLine, + { + "objectHandle" : text, + "font" : textLine.font, + "fontWidth" : textLine.fontWidth, + }) + } + } +} + diff --git a/yat/yat_declarative/qml/yat_declarative/TerminalScreen.qml b/yat/yat_declarative/qml/yat_declarative/TerminalScreen.qml new file mode 100644 index 0000000..5cf7f87 --- /dev/null +++ b/yat/yat_declarative/qml/yat_declarative/TerminalScreen.qml @@ -0,0 +1,194 @@ +import QtQuick 2.0 + +import org.yat 1.0 + +TerminalScreen { + id: screenItem + + property font font + property real fontWidth: fontMetricText.paintedWidth + property real fontHeight: fontMetricText.paintedHeight + + property var lineComponent : Qt.createComponent("TerminalLine.qml") + + font.family: "courier" + + Text { + id: fontMetricText + text: "B" + font: parent.font + visible: false + textFormat: Text.PlainText + } + + Rectangle { + id: background + anchors.fill: parent + color: "black" + } + + Connections { + id: connections + + target: terminal.screen + + onFlash: { + flashAnimation.start() + } + + onCursorPositionChanged: { + cursor.x = x * fontWidth; + cursor.y = y * fontHeight; + } + + onReset: { + resetScreenItems(); + } + + onLineCreated: { + var lineVariable = lineComponent.createObject(screenItem, + { + "objectHandle" : line, + "font": screenItem.font, + "fontWidth" : screenItem.fontWidth, + "fontHeight" : screenItem.fontHeight, + }) + } + } + + onFontChanged: { + setTerminalHeight(); + setTerminalWidth(); + } + + onWidthChanged: { + setTerminalWidth(); + } + onHeightChanged: { + setTerminalHeight(); + } + Component.onCompleted: { + setTerminalWidth(); + setTerminalHeight(); + } + + function setTerminalWidth() { + if (fontWidth > 0) { + var pty_width = Math.floor(width / fontWidth); + screen.width = pty_width; + } + } + + function setTerminalHeight() { + if (fontHeight > 0) { + var pty_height = Math.floor(height / fontHeight); + screen.height = pty_height; + } + } + + + Item { + id: keyHandler + focus: true + Keys.onPressed: { + terminal.screen.sendKey(event.text, event.key, event.modifiers); + if (event.text === "?") { + terminal.screen.printScreen() + } + } + } + + HighlightArea { + characterHeight: fontHeight + characterWidth: fontWidth + + start: screen.selectionAreaStart + end: screen.selectionAreaEnd + + visible: screen.selectionEnabled + } + + Rectangle { + id: cursor + width: fontWidth + height: fontHeight + x: 0 + y: 0 + color: "grey" + } + + Rectangle { + id: flash + anchors.fill: parent + color: "grey" + opacity: 0 + SequentialAnimation { + id: flashAnimation + NumberAnimation { + target: flash + property: "opacity" + to: 1 + duration: 75 + } + NumberAnimation { + target: flash + property: "opacity" + to: 0 + duration: 75 + } + } + } + + MouseArea { + id:mousArea + + property point drag_start + + anchors.fill: parent + acceptedButtons: Qt.LeftButton | Qt.MiddleButton + onPressed: { + if (mouse.button == Qt.LeftButton) { + hoverEnabled = true; + var character = Math.floor((mouse.x / screen.charWidth)); + var line = Math.floor(mouse.y / screen.lineHeight); + var start = Qt.point(character,line); + drag_start = start; + screen.selectionAreaStart = start; + screen.selectionAreaEnd = start; + } + } + + onPositionChanged: { + var character = Math.floor(mouse.x / screen.charWidth); + var line = Math.floor(mouse.y / screen.lineHeight); + var current_pos = Qt.point(character,line); + if (line < drag_start.y || (line === drag_start.y && character < drag_start.x)) { + screen.selectionAreaStart = current_pos; + screen.selectionAreaEnd = drag_start; + }else { + screen.selectionAreaEnd = current_pos; + screen.selectionAreaStart = drag_start; + } + } + + onReleased: { + if (mouse.button == Qt.LeftButton) { + hoverEnabled = false; + screen.sendSelectionToSelection(); + } + } + + onClicked: { + if (mouse.button == Qt.MiddleButton) { + screen.pasteFromSelection(); + } + } + onDoubleClicked: { + if (mouse.button == Qt.LeftButton) { + var character = Math.floor(mouse.x / screen.charWidth); + var line = Math.floor(mouse.y / screen.lineHeight); + screen.doubleClicked(Qt.point(character,line)); + } + } + } +} diff --git a/yat/yat_declarative/qml/yat_declarative/TerminalText.qml b/yat/yat_declarative/qml/yat_declarative/TerminalText.qml new file mode 100644 index 0000000..8b805d6 --- /dev/null +++ b/yat/yat_declarative/qml/yat_declarative/TerminalText.qml @@ -0,0 +1,78 @@ +/******************************************************************************* +* Copyright (c) 2013 Jørgen Lind +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +*******************************************************************************/ + +import QtQuick 2.0 + +import org.yat 1.0 + +ObjectDestructItem { + id: textItem + property font font + property real fontWidth + + y: 0 + x: 0 + + width: textElement.paintedWidth + height: textElement.paintedHeight + + visible: objectHandle.visible + + Rectangle { + anchors.fill: parent + color: textItem.objectHandle.backgroundColor + } + + + Text { + id: textElement + anchors.fill: parent + text: objectHandle.text + color: objectHandle.foregroundColor + font: textItem.font + textFormat: Text.PlainText + } + + Connections { + target: objectHandle + + onIndexChanged: { + textItem.x = objectHandle.index * textItem.fontWidth; + } + } + + //Component.onCompleted: { + // //color = randomBg(); + //} + //function randomBg() + //{ + // var hex1=new Array("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F") + // var hex2=new Array("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F") + // var hex3=new Array("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F") + // var hex4=new Array("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F") + // var hex5=new Array("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F") + // var hex6=new Array("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F") + // var bg="#"+hex1[Math.floor(Math.random()*hex1.length)]+hex2[Math.floor(Math.random()*hex2.length)]+hex3[Math.floor(Math.random()*hex3.length)]+hex4[Math.floor(Math.random()*hex4.length)]+hex5[Math.floor(Math.random()*hex5.length)]+hex6[Math.floor(Math.random()*hex6.length)] + // return bg + //} +} diff --git a/yat/yat_declarative/qml/yat_declarative/main.qml b/yat/yat_declarative/qml/yat_declarative/main.qml new file mode 100644 index 0000000..72ca9c3 --- /dev/null +++ b/yat/yat_declarative/qml/yat_declarative/main.qml @@ -0,0 +1,7 @@ +import QtQuick 2.0 + +TerminalScreen { + id: terminal + width: 800 + height: 600 +} diff --git a/yat/yat_declarative/qml_sources.qrc b/yat/yat_declarative/qml_sources.qrc new file mode 100644 index 0000000..21c81e6 --- /dev/null +++ b/yat/yat_declarative/qml_sources.qrc @@ -0,0 +1,9 @@ + + + qml/yat_declarative/main.qml + qml/yat_declarative/TerminalLine.qml + qml/yat_declarative/TerminalScreen.qml + qml/yat_declarative/TerminalText.qml + qml/yat_declarative/HighlightArea.qml + + diff --git a/yat/yat_declarative/register_qml_types.cpp b/yat/yat_declarative/register_qml_types.cpp new file mode 100644 index 0000000..64e1019 --- /dev/null +++ b/yat/yat_declarative/register_qml_types.cpp @@ -0,0 +1,18 @@ +#include "register_qml_types.h" + +#include + +#include "terminal_screen.h" +#include "object_destruct_item.h" +#include "screen.h" +#include "text.h" +#include "line.h" + +void register_qml_types() +{ + qmlRegisterType("org.yat", 1, 0, "TerminalScreen"); + qmlRegisterType("org.yat", 1, 0, "ObjectDestructItem"); + qmlRegisterType(); + qmlRegisterType(); + qmlRegisterType(); +} diff --git a/yat/yat_declarative/register_qml_types.h b/yat/yat_declarative/register_qml_types.h new file mode 100644 index 0000000..5b036c6 --- /dev/null +++ b/yat/yat_declarative/register_qml_types.h @@ -0,0 +1,6 @@ +#ifndef REGISTER_QML_TYPES_H +#define REGISTER_QML_TYPES_H + +void register_qml_types(); + +#endif // REGISTER_QML_TYPES_H diff --git a/yat/yat_declarative/terminal_screen.cpp b/yat/yat_declarative/terminal_screen.cpp new file mode 100644 index 0000000..944cba6 --- /dev/null +++ b/yat/yat_declarative/terminal_screen.cpp @@ -0,0 +1,32 @@ +/************************************************************************************************** +* Copyright (c) 2012 Jørgen Lind +* +* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +* associated documentation files (the "Software"), to deal in the Software without restriction, +* including without limitation the rights to use, copy, modify, merge, publish, distribute, +* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all copies or +* substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT +* NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +* OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +***************************************************************************************************/ + +#include "terminal_screen.h" + +TerminalScreen::TerminalScreen(QQuickItem *parent) + : QQuickItem(parent) + , m_screen(new Screen(this)) +{ +} + +Screen *TerminalScreen::screen() const +{ + return m_screen; +} diff --git a/yat/yat_declarative/terminal_screen.h b/yat/yat_declarative/terminal_screen.h new file mode 100644 index 0000000..ab0d618 --- /dev/null +++ b/yat/yat_declarative/terminal_screen.h @@ -0,0 +1,46 @@ +/****************************************************************************** +* Copyright (c) 2012 Jørgen Lind +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +******************************************************************************/ + +#ifndef TERMINALITEM_H +#define TERMINALITEM_H + +#include +#include + +#include "screen.h" + +class TerminalScreen : public QQuickItem +{ + Q_OBJECT + + Q_PROPERTY(Screen *screen READ screen CONSTANT) +public: + TerminalScreen(QQuickItem *parent = 0); + + Screen *screen() const; + +private: + Screen *m_screen; +}; + +#endif // TERMINALITEM_H diff --git a/yat/yat_declarative/yat_declarative.pro b/yat/yat_declarative/yat_declarative.pro new file mode 100644 index 0000000..2932b14 --- /dev/null +++ b/yat/yat_declarative/yat_declarative.pro @@ -0,0 +1,27 @@ +QT += gui quick +TARGET = yat + +include(../backend/backend.pri) + +SOURCES += main.cpp \ + terminal_screen.cpp \ + object_destruct_item.cpp \ + register_qml_types.cpp \ + +HEADERS += \ + terminal_screen.h \ + object_destruct_item.h \ + register_qml_types.h \ + +QML_IMPORT_PATH = + +OTHER_FILES += \ + qml/yat_declarative/main.qml \ + qml/yat_declarative/TerminalLine.qml \ + qml/yat_declarative/TerminalScreen.qml \ + qml/yat_declarative/TerminalText.qml \ + qml/yat_declarative/HighlightArea.qml + +RESOURCES += \ + qml_sources.qrc +