default void handleCsi(ByteBuffer csiParam, ByteBuffer csiInter, byte csiFinal)
			throws Exception {
		try {
			switch (csiFinal) {
				case '@': { // Insert characters
					OfInt bits = parseCsiInts(csiParam);
					int n = bits.hasNext() ? bits.nextInt() : 1;
					handleInsertCharacters(n);
					return;
				}
				case 'A': // Cursor up
				case 'B': // Cursor down
				case 'C': // Cursor forward
				case 'D': /* Cursor back */ {
					Direction dir = Direction.forCsiFinal(csiFinal);
					OfInt bits = parseCsiInts(csiParam);
					int n = bits.hasNext() ? bits.nextInt() : 1;
					handleMoveCursor(dir, n);
					return;
				}
				case 'G': { // Cursor character absolute
					OfInt bits = parseCsiInts(csiParam);
					int n = bits.hasNext() ? bits.nextInt() : 1;
					handleMoveCursorCol(n - 1);
					return;
				}
				case 'H': { // Cursor position
					OfInt bits = parseCsiInts(csiParam);
					int n = bits.hasNext() ? bits.nextInt() : 1;
					int m = bits.hasNext() ? bits.nextInt() : 1;
					handleMoveCursor(n - 1, m - 1);
					return;
				}
				case 'J': { // Erase in display
					OfInt bits = parseCsiInts(csiParam);
					int n = bits.hasNext() ? bits.nextInt() : 0;
					handleErase(Erasure.fromED(n));
					return;
				}
				case 'K': { // Erase in line
					OfInt bits = parseCsiInts(csiParam);
					int n = bits.hasNext() ? bits.nextInt() : 0;
					handleErase(Erasure.fromEL(n));
					return;
				}
				case 'L': { // Insert lines
					OfInt bits = parseCsiInts(csiParam);
					int n = bits.hasNext() ? bits.nextInt() : 1;
					handleInsertLines(n);
					return;
				}
				case 'M': { // Delete lines
					OfInt bits = parseCsiInts(csiParam);
					int n = bits.hasNext() ? bits.nextInt() : 1;
					handleDeleteLines(n);
					return;
				}
				case 'P': { // Delete characters
					OfInt bits = parseCsiInts(csiParam);
					int n = bits.hasNext() ? bits.nextInt() : 1;
					handleDeleteCharacters(n);
					return;
				}
				case 'S': { // Scroll up lines
					OfInt bits = parseCsiInts(csiParam);
					int n = bits.hasNext() ? bits.nextInt() : 1;
					handleScrollLinesUp(n, false);
					return;
				}
				case 'T': { // Scroll down lines
					OfInt bits = parseCsiInts(csiParam);
					int n = bits.hasNext() ? bits.nextInt() : 1;
					handleScrollLinesDown(n);
					return;
				}
				case 'X': { // Erase characters
					OfInt bits = parseCsiInts(csiParam);
					int n = bits.hasNext() ? bits.nextInt() : 1;
					handleEraseCharacters(n);
					return;
				}
				case 'Z': { // Cursor backward tabulation
					OfInt bits = parseCsiInts(csiParam);
					int n = bits.hasNext() ? bits.nextInt() : 1;
					handleBackwardTab(n);
					return;
				}
				case 'c': { // Send Device Attributes
					Msg.trace(this, "TODO: Send Device Attributes");
					return;
				}
				case 'd': { // Line position absolute
					OfInt bits = parseCsiInts(csiParam);
					int n = bits.hasNext() ? bits.nextInt() : 1;
					handleMoveCursorRow(n - 1);
					return;
				}
				case 'h': {
					handleHOrLStuff(csiParam, true);
					return;
				}
				case 'l': {
					handleHOrLStuff(csiParam, false);
					return;
				}
				case 'm': { // Select Graphic Rendition (SGR)
					if (csiParam.hasRemaining()) {
						switch (csiParam.get(csiParam.position())) {
							case '>': // Set key modifier options
								Msg.trace(this, "TODO: Set key modifier options");
								return;
							case '?': // Query key modifier options
								Msg.trace(this, "TODO: Query key modifier options");
								return;
						}
					}
					OfInt bits = parseCsiInts(csiParam);
					if (!bits.hasNext()) {
						handleResetAttributes();
					}
					while (bits.hasNext()) {
						handleSgrAttribute(bits);
					}
					return;
				}
				case 'n': { // Device Status Report
					OfInt bits = parseCsiInts(csiParam);
					if (!bits.hasNext()) {
						throw new UnknownCsiException();
					}
					switch (bits.nextInt()) {
						case 6: // Report Cursor Position
							handleReportCursorPos();
							return;
						case 5: // Status Report (Not implemented)
						default:
							throw new UnknownCsiException();
					}
				}
				case 'p': { // Soft terminal reset
					// TODO: Not sure how/if this should differ from "full" reset
					handleFullReset();
					return;
				}
				case 'r': { // Scroll screen
					OfInt bits = parseCsiInts(csiParam);
					Integer start = bits.hasNext() ? bits.nextInt() - 1 : null;
					Integer end = bits.hasNext() ? bits.nextInt() - 1 : null;
					handleSetScrollRange(start, end);
					return;
				}
				case 's': {
					handleSaveCursorPos();
					return;
				}
				case 't': { // Window manipulation
					handleWindowManipulation(csiParam);
					return;
				}
				case 'u': {
					handleRestoreCursorPos();
					return;
				}
				default: {
					throw new UnknownCsiException();
				}
			}
		}
		catch (UnknownCsiException e) {
			Msg.error(this, "Unknown CSI sequence: param:'" +
				strBuf(csiParam) + "' inter:'" + strBuf(csiInter) + "' final:" +
				charInfo(csiFinal));
		}
		return;
	}
Handle a CSI sequence

@param csiParam the parameter buffer
@param csiInter the intermediate buffer
@param csiFinal the final byte
@throws Exception if anything goes wrong
Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/terminal/vt/VtHandler.java