Эх сурвалжийг харах

Various memory leak fixes in Terminal

Miguel de Icaza 3 жил өмнө
parent
commit
43ca63b501

+ 2 - 5
Sources/SwiftTerm/EscapeSequenceParser.swift

@@ -284,6 +284,7 @@ class EscapeSequenceParser {
     var executeHandlers: [UInt8:ExecuteHandler] = [:]
     var escHandlers: [cstring:EscHandler] = [:]
     var dcsHandlers: [cstring:DcsHandler] = [:]
+    
     var activeDcsHandler: DcsHandler? = nil
     var errorHandler: (ParsingState) -> ParsingState = { (state : ParsingState) -> ParsingState in return state; }
     
@@ -308,11 +309,7 @@ class EscapeSequenceParser {
         _parsTxt = []
         _collect = []
         // "\"
-        setEscHandler("\\", ParserEscHandlerFallback)
-    }
-    
-    func ParserEscHandlerFallback (collect: cstring, flag: UInt8)
-    {
+        setEscHandler("\\", { collect, flag in })
     }
     
     var escHandlerFallback: EscHandlerFallback = { (collect: cstring, flag: UInt8) in

+ 2 - 2
Sources/SwiftTerm/LocalProcess.swift

@@ -67,7 +67,7 @@ public class LocalProcess {
     var sendCount = 0
     var total = 0
 
-    weak var delegate: LocalProcessDelegate?
+    unowned var delegate: LocalProcessDelegate?
     
     // Queue used to send the data received from the local process
     var dispatchQueue: DispatchQueue
@@ -206,7 +206,7 @@ public class LocalProcess {
                 } else {
                     // Fallback on earlier versions
                 }
-                cm.setEventHandler(handler: processTerminated)
+                cm.setEventHandler(handler: { [weak self] in self?.processTerminated () })
             }
             
             running = true

+ 2 - 2
Sources/SwiftTerm/Mac/MacLocalTerminalView.swift

@@ -8,7 +8,7 @@
 #if os(macOS)
 import Foundation
 
-public protocol LocalProcessTerminalViewDelegate {
+public protocol LocalProcessTerminalViewDelegate: AnyObject {
     /**
      * This method is invoked to notify that the terminal has been resized to the specified number of columns and rows
      * the user interface code might try to adjut the containing scroll view, or if it is a toplevel window, the window itself
@@ -82,7 +82,7 @@ public class LocalProcessTerminalView: TerminalView, TerminalViewDelegate, Local
     /**
      * The `processDelegate` is used to deliver messages and information relevant t
      */
-    public var processDelegate: LocalProcessTerminalViewDelegate?
+    public weak var processDelegate: LocalProcessTerminalViewDelegate?
     
     /**
      * This method is invoked to notify the client of the new columsn and rows that have been set by the UI

+ 1 - 1
Sources/SwiftTerm/SixelDcsHandler.swift

@@ -11,7 +11,7 @@ import Foundation
 // into its internal representation to display the image.
 class SixelDcsHandler : DcsHandler {
     var data: [UInt8]
-    var terminal: Terminal
+    unowned var terminal: Terminal
 
     public init (terminal: Terminal)
     {

+ 125 - 119
Sources/SwiftTerm/Terminal.swift

@@ -488,8 +488,13 @@ open class Terminal {
         return (cols, rows)
     }
     
+    class Demo {
+        
+    }
+    
     public init (delegate : TerminalDelegate, options: TerminalOptions = TerminalOptions.default)
     {
+        let a = Demo()
         installedColors = Color.defaultInstalledColors
         defaultAnsiColors = Color.setupDefaultAnsiColors (initialColors: installedColors)
         ansiColors = defaultAnsiColors
@@ -639,7 +644,7 @@ open class Terminal {
     // Response: DECRPSS (https://vt100.net/docs/vt510-rm/DECRPSS.html)
     class DECRQSS : DcsHandler {
         var data: [UInt8]
-        var terminal: Terminal
+        unowned var terminal: Terminal
 
         public init (terminal: Terminal)
         {
@@ -694,116 +699,116 @@ open class Terminal {
     // Configures the EscapeSequenceParser
     func configureParser (_ parser: EscapeSequenceParser)
     {
-        parser.csiHandlerFallback = { (pars: [Int], collect: cstring, code: UInt8) -> () in
+        parser.csiHandlerFallback = { [unowned self] (pars: [Int], collect: cstring, code: UInt8) -> () in
             let ch = Character(UnicodeScalar(code))
             self.log ("Unknown CSI Code (collect=\(collect) code=\(ch) pars=\(pars))")
         }
-        parser.escHandlerFallback = { (txt: cstring, flag: UInt8) in
+        parser.escHandlerFallback = { [unowned self] (txt: cstring, flag: UInt8) in
             self.log ("Unknown ESC Code: ESC + \(Character(Unicode.Scalar (flag))) txt=\(txt)")
         }
-        parser.executeHandlerFallback = {
+        parser.executeHandlerFallback = { [unowned self] in
             self.log ("Unknown EXECUTE code")
         }
-        parser.oscHandlerFallback = { (code: Int) in
+        parser.oscHandlerFallback = { [unowned self] (code: Int) in
             self.log ("Unknown OSC code: \(code)")
         }
-        parser.printHandler = handlePrint
-        parser.printStateReset = printStateReset
+        parser.printHandler = { [unowned self] slice in handlePrint (slice) }
+        parser.printStateReset = { [unowned self] in printStateReset() }
         
         // CSI handler
-        parser.csiHandlers [UInt8 (ascii: "@")] = cmdInsertChars
-        parser.csiHandlers [UInt8 (ascii: "A")] = cmdCursorUp
-        parser.csiHandlers [UInt8 (ascii: "B")] = cmdCursorDown
-        parser.csiHandlers [UInt8 (ascii: "C")] = cmdCursorForward
-        parser.csiHandlers [UInt8 (ascii: "D")] = cmdCursorBackward
-        parser.csiHandlers [UInt8 (ascii: "E")] = cmdCursorNextLine
-        parser.csiHandlers [UInt8 (ascii: "F")] = cmdCursorPrecedingLine
-        parser.csiHandlers [UInt8 (ascii: "G")] = cmdCursorCharAbsolute
-        parser.csiHandlers [UInt8 (ascii: "H")] = cmdCursorPosition
-        parser.csiHandlers [UInt8 (ascii: "I")] = cmdCursorForwardTab
-        parser.csiHandlers [UInt8 (ascii: "J")] = cmdEraseInDisplay
-        parser.csiHandlers [UInt8 (ascii: "K")] = cmdEraseInLine
-        parser.csiHandlers [UInt8 (ascii: "L")] = cmdInsertLines
-        parser.csiHandlers [UInt8 (ascii: "M")] = cmdDeleteLines
-        parser.csiHandlers [UInt8 (ascii: "P")] = cmdDeleteChars
-        parser.csiHandlers [UInt8 (ascii: "S")] = cmdScrollUp
-        parser.csiHandlers [UInt8 (ascii: "T")] = csiT
-        parser.csiHandlers [UInt8 (ascii: "X")] = cmdEraseChars
-        parser.csiHandlers [UInt8 (ascii: "Z")] = cmdCursorBackwardTab
-        parser.csiHandlers [UInt8 (ascii: "`")] = cmdCharPosAbsolute
-        parser.csiHandlers [UInt8 (ascii: "a")] = cmdHPositionRelative
-        parser.csiHandlers [UInt8 (ascii: "b")] = cmdRepeatPrecedingCharacter
-        parser.csiHandlers [UInt8 (ascii: "c")] = cmdSendDeviceAttributes
-        parser.csiHandlers [UInt8 (ascii: "d")] = cmdLinePosAbsolute
-        parser.csiHandlers [UInt8 (ascii: "e")] = cmdVPositionRelative
-        parser.csiHandlers [UInt8 (ascii: "f")] = cmdHVPosition
-        parser.csiHandlers [UInt8 (ascii: "g")] = cmdTabClear
-        parser.csiHandlers [UInt8 (ascii: "h")] = cmdSetMode
-        parser.csiHandlers [UInt8 (ascii: "l")] = cmdResetMode
-        parser.csiHandlers [UInt8 (ascii: "m")] = cmdCharAttributes
-        parser.csiHandlers [UInt8 (ascii: "n")] = cmdDeviceStatus
-        parser.csiHandlers [UInt8 (ascii: "p")] = csiPHandler
-        parser.csiHandlers [UInt8 (ascii: "q")] = cmdSetCursorStyle
-        parser.csiHandlers [UInt8 (ascii: "r")] = cmdSetScrollRegion
-        parser.csiHandlers [UInt8 (ascii: "s")] = { [weak self] args, cstring in
+        parser.csiHandlers [UInt8 (ascii: "@")] = { [unowned self] pars, collect in cmdInsertChars (pars, collect) }
+        parser.csiHandlers [UInt8 (ascii: "A")] = { [unowned self] pars, collect in cmdCursorUp (pars, collect) }
+        parser.csiHandlers [UInt8 (ascii: "B")] = { [unowned self] pars, collect in cmdCursorDown (pars, collect) }
+        parser.csiHandlers [UInt8 (ascii: "C")] = { [unowned self] pars, collect in cmdCursorForward (pars, collect) }
+        parser.csiHandlers [UInt8 (ascii: "D")] = { [unowned self] pars, collect in cmdCursorBackward (pars, collect) }
+        parser.csiHandlers [UInt8 (ascii: "E")] = { [unowned self] pars, collect in cmdCursorNextLine (pars, collect) }
+        parser.csiHandlers [UInt8 (ascii: "F")] = { [unowned self] pars, collect in cmdCursorPrecedingLine (pars, collect) }
+        parser.csiHandlers [UInt8 (ascii: "G")] = { [unowned self] pars, collect in cmdCursorCharAbsolute (pars, collect) }
+        parser.csiHandlers [UInt8 (ascii: "H")] = { [unowned self] pars, collect in cmdCursorPosition (pars, collect) }
+        parser.csiHandlers [UInt8 (ascii: "I")] = { [unowned self] pars, collect in cmdCursorForwardTab (pars, collect) }
+        parser.csiHandlers [UInt8 (ascii: "J")] = { [unowned self] pars, collect in cmdEraseInDisplay (pars, collect) }
+        parser.csiHandlers [UInt8 (ascii: "K")] = { [unowned self] pars, collect in cmdEraseInLine (pars, collect) }
+        parser.csiHandlers [UInt8 (ascii: "L")] = { [unowned self] pars, collect in cmdInsertLines (pars, collect) }
+        parser.csiHandlers [UInt8 (ascii: "M")] = { [unowned self] pars, collect in cmdDeleteLines (pars, collect) }
+        parser.csiHandlers [UInt8 (ascii: "P")] = { [unowned self] pars, collect in cmdDeleteChars (pars, collect) }
+        parser.csiHandlers [UInt8 (ascii: "S")] = { [unowned self] pars, collect in cmdScrollUp (pars, collect) }
+        parser.csiHandlers [UInt8 (ascii: "T")] = { [unowned self] pars, collect in csiT (pars, collect) }
+        parser.csiHandlers [UInt8 (ascii: "X")] = { [unowned self] pars, collect in cmdEraseChars (pars, collect) }
+        parser.csiHandlers [UInt8 (ascii: "Z")] = { [unowned self] pars, collect in cmdCursorBackwardTab (pars, collect) }
+        parser.csiHandlers [UInt8 (ascii: "`")] = { [unowned self] pars, collect in cmdCharPosAbsolute (pars, collect) }
+        parser.csiHandlers [UInt8 (ascii: "a")] = { [unowned self] pars, collect in cmdHPositionRelative (pars, collect) }
+        parser.csiHandlers [UInt8 (ascii: "b")] = { [unowned self] pars, collect in cmdRepeatPrecedingCharacter (pars, collect) }
+        parser.csiHandlers [UInt8 (ascii: "c")] = { [unowned self] pars, collect in cmdSendDeviceAttributes (pars, collect) }
+        parser.csiHandlers [UInt8 (ascii: "d")] = { [unowned self] pars, collect in cmdLinePosAbsolute (pars, collect) }
+        parser.csiHandlers [UInt8 (ascii: "e")] = { [unowned self] pars, collect in cmdVPositionRelative (pars, collect) }
+        parser.csiHandlers [UInt8 (ascii: "f")] = { [unowned self] pars, collect in cmdHVPosition (pars, collect) }
+        parser.csiHandlers [UInt8 (ascii: "g")] = { [unowned self] pars, collect in cmdTabClear (pars, collect) }
+        parser.csiHandlers [UInt8 (ascii: "h")] = { [unowned self] pars, collect in cmdSetMode (pars, collect) }
+        parser.csiHandlers [UInt8 (ascii: "l")] = { [unowned self] pars, collect in cmdResetMode (pars, collect) }
+        parser.csiHandlers [UInt8 (ascii: "m")] = { [unowned self] pars, collect in cmdCharAttributes (pars, collect) }
+        parser.csiHandlers [UInt8 (ascii: "n")] = { [unowned self] pars, collect in cmdDeviceStatus (pars, collect) }
+        parser.csiHandlers [UInt8 (ascii: "p")] = { [unowned self] pars, collect in csiPHandler (pars, collect) }
+        parser.csiHandlers [UInt8 (ascii: "q")] = { [unowned self] pars, collect in cmdSetCursorStyle (pars, collect) }
+        parser.csiHandlers [UInt8 (ascii: "r")] = { [unowned self] pars, collect in cmdSetScrollRegion (pars, collect) }
+        parser.csiHandlers [UInt8 (ascii: "s")] = { [unowned self] args, cstring in
             // "CSI s" is overloaded, can mean save cursor, but also set the margins with DECSLRM
-            if self!.marginMode {
-                self!.cmdSetMargins (args, cstring)
+            if self.marginMode {
+                self.cmdSetMargins (args, cstring)
             } else {
-                self!.cmdSaveCursor (args, cstring)
+                self.cmdSaveCursor (args, cstring)
             }
         }
-        parser.csiHandlers [UInt8 (ascii: "t")] = csit
-        parser.csiHandlers [UInt8 (ascii: "u")] = cmdRestoreCursor
-        parser.csiHandlers [UInt8 (ascii: "v")] = csiCopyRectangularArea
-        parser.csiHandlers [UInt8 (ascii: "x")] = csiX                    /* x DECFRA - could be overloaded */
-        parser.csiHandlers [UInt8 (ascii: "y")] = cmdDECRQCRA             /* y - Checksum Region */
-        parser.csiHandlers [UInt8 (ascii: "z")] = csiZ /* DECERA */
-        parser.csiHandlers [UInt8 (ascii: "{")] = csiOpenBrace
-        parser.csiHandlers [UInt8 (ascii: "}")] = csiCloseBrace
-        parser.csiHandlers [UInt8 (ascii: "~")] = cmdDeleteColumns
-
-        parser.executeHandlers [7]  = { [weak self] in self!.tdel?.bell (source: self!) }
-        parser.executeHandlers [10] = cmdLineFeed
-        parser.executeHandlers [11] = cmdLineFeedBasic   // VT Vertical Tab - ignores auto-new-line behavior in ConvertEOL
-        parser.executeHandlers [12] = cmdLineFeedBasic
-        parser.executeHandlers [13] = cmdCarriageReturn
-        parser.executeHandlers [8]  = cmdBackspace
-        parser.executeHandlers [9]  = cmdTab
-        parser.executeHandlers [14] = cmdShiftOut
-        parser.executeHandlers [15] = cmdShiftIn
+        parser.csiHandlers [UInt8 (ascii: "t")] = { [unowned self] pars, collect in csit (pars, collect) }
+        parser.csiHandlers [UInt8 (ascii: "u")] = { [unowned self] pars, collect in cmdRestoreCursor (pars, collect) }
+        parser.csiHandlers [UInt8 (ascii: "v")] = { [unowned self] pars, collect in csiCopyRectangularArea (pars, collect) }
+        parser.csiHandlers [UInt8 (ascii: "x")] = { [unowned self] pars, collect in csiX (pars, collect) } /* x DECFRA - could be overloaded */
+        parser.csiHandlers [UInt8 (ascii: "y")] = { [unowned self] pars, collect in cmdDECRQCRA (pars, collect) } /* y - Checksum Region */
+        parser.csiHandlers [UInt8 (ascii: "z")] = { [unowned self] pars, collect in csiZ (pars, collect) } /* DECERA */
+        parser.csiHandlers [UInt8 (ascii: "{")] = { [unowned self] pars, collect in csiOpenBrace (pars, collect) }
+        parser.csiHandlers [UInt8 (ascii: "}")] = { [unowned self] pars, collect in csiCloseBrace (pars, collect) }
+        parser.csiHandlers [UInt8 (ascii: "~")] = { [unowned self] pars, collect in cmdDeleteColumns (pars, collect) }
+
+        parser.executeHandlers [7]  = { [unowned self] in self.tdel?.bell (source: self) }
+        parser.executeHandlers [10] = { [unowned self] in cmdLineFeed () }
+        parser.executeHandlers [11] = { [unowned self] in cmdLineFeedBasic () }  // VT Vertical Tab - ignores auto-new-line behavior in ConvertEOL
+        parser.executeHandlers [12] = { [unowned self] in cmdLineFeedBasic () }
+        parser.executeHandlers [13] = { [unowned self] in cmdCarriageReturn () }
+        parser.executeHandlers [8]  = { [unowned self] in cmdBackspace () }
+        parser.executeHandlers [9]  = { [unowned self] in cmdTab () }
+        parser.executeHandlers [14] = { [unowned self] in cmdShiftOut () }
+        parser.executeHandlers [15] = { [unowned self] in cmdShiftIn () }
         
-        parser.executeHandlers [0x84] = cmdIndex
-        parser.executeHandlers [0x85] = cmdNextLine
-        parser.executeHandlers [0x88] = cmdTabSet
+        parser.executeHandlers [0x84] = { [unowned self] in cmdIndex () }
+        parser.executeHandlers [0x85] = { [unowned self] in cmdNextLine () }
+        parser.executeHandlers [0x88] = {  [unowned self] in cmdTabSet () }
 
         //
         // OSC handler
         //
         //   0 - icon name + title
-        parser.oscHandlers [0] = { data in self.setTitle(text: String (bytes: data, encoding: .utf8) ?? "")}
+        parser.oscHandlers [0] = { [unowned self] data in self.setTitle(text: String (bytes: data, encoding: .utf8) ?? "")}
         //   1 - icon name
-        parser.oscHandlers [1] = { data in self.setIconTitle(text: String (bytes: data, encoding: .utf8) ?? "") }
+        parser.oscHandlers [1] = { [unowned self] data in self.setIconTitle(text: String (bytes: data, encoding: .utf8) ?? "") }
         //   2 - title
-        parser.oscHandlers [2] = { data in self.setTitle(text: String (bytes: data, encoding: .utf8) ?? "")}
+        parser.oscHandlers [2] = { [unowned self] data in self.setTitle(text: String (bytes: data, encoding: .utf8) ?? "")}
         //   3 - set property X in the form "prop=value"
         //   4 - Change Color Number()
-        parser.oscHandlers [4] = oscChangeOrQueryColorIndex
+        parser.oscHandlers [4] = { [unowned self] data in oscChangeOrQueryColorIndex (data) }
         
         //   5 - Change Special Color Number
         //   6 - Enable/disable Special Color Number c
 
         //   6 - current document:
-        parser.oscHandlers [6] = oscSetCurrentDocument
+        parser.oscHandlers [6] = { [unowned self] data in oscSetCurrentDocument (data) }
 
         //   7 - current directory? (not in xterm spec, see https://gitlab.com/gnachman/iterm2/issues/3939)
-        parser.oscHandlers [7] = oscSetCurrentDirectory
+        parser.oscHandlers [7] = { [unowned self] data in oscSetCurrentDirectory (data) }
         
-        parser.oscHandlers [8] = oscHyperlink
+        parser.oscHandlers [8] = { [unowned self] data in oscHyperlink (data) }
         //  10 - Change VT100 text foreground color to Pt.
-        parser.oscHandlers [10] = oscSetTextForeground
+        parser.oscHandlers [10] = { [unowned self] data in oscSetTextForeground (data) }
         //  11 - Change VT100 text background color to Pt.
-        parser.oscHandlers [11] = oscSetTextBackground
+        parser.oscHandlers [11] = { [unowned self] data in oscSetTextBackground (data) }
         //  12 - Change text cursor color to Pt.
         //  13 - Change mouse foreground color to Pt.
         //  14 - Change mouse background color to Pt.
@@ -816,9 +821,9 @@ open class Terminal {
         //  50 - Set Font to Pt.
         //  51 - reserved for Emacs shell.
         //  52 - Clipboard operations
-        parser.oscHandlers [52] = oscClipboard
+        parser.oscHandlers [52] = { [unowned self] data in oscClipboard (data) }
         // 104 ; c - Reset Color Number c.
-        parser.oscHandlers [104] = oscResetColor
+        parser.oscHandlers [104] = { [unowned self] data in oscResetColor (data) }
         
         // 105 ; c - Reset Special Color Number c.
         // 106 ; c; f - Enable/disable Special Color Number c.
@@ -829,47 +834,48 @@ open class Terminal {
         // 114 - Reset mouse background color.
         // 115 - Reset Tektronix foreground color.
         // 116 - Reset Tektronix background color.
-        parser.oscHandlers [777] = oscNotification
-        parser.oscHandlers [1337] = osciTerm2
+        parser.oscHandlers [777] = { [unowned self] data in oscNotification (data) }
+        parser.oscHandlers [1337] = { [unowned self] data in osciTerm2 (data) }
 
         //
         // ESC handlers
         //
-        parser.setEscHandler("6", { collect, flags in self.columnIndex (back: true) })
-        parser.setEscHandler ("7",  { collect, flag in self.cmdSaveCursor ([], []) })
-        parser.setEscHandler ("8",  { collect, flag in self.cmdRestoreCursor ([], []) })
-        parser.setEscHandler ("9",  { collect, flag in self.columnIndex(back: false) })
-        parser.setEscHandler ("D",  { collect, flag in self.cmdIndex() })
-        parser.setEscHandler ("E",  { collect, flag in self.cmdNextLine () })
-        parser.setEscHandler ("H",  { collect, flag in self.cmdTabSet ()})
-        parser.setEscHandler ("M",  { collect, flag in self.reverseIndex() })
-        parser.setEscHandler ("=",  { collect, flags in self.cmdKeypadApplicationMode ()})
-        parser.setEscHandler (">",  { collect, flags in self.cmdKeypadNumericMode ()})
-        parser.setEscHandler ("c",  { collect, flags in self.cmdReset () })
-        parser.setEscHandler ("n",  { collect, flag in self.setgLevel (2) })
-        parser.setEscHandler ("o",  { collect, flag in self.setgLevel (3) })
-        parser.setEscHandler ("|",  { collect, flag in self.setgLevel (3) })
-        parser.setEscHandler ("}",  { collect, flag in self.setgLevel (2) })
-        parser.setEscHandler ("~",  { collect, flag in self.setgLevel (1) })
-        parser.setEscHandler ("%@", { collect, flag in self.cmdSelectDefaultCharset () })
-        parser.setEscHandler ("%G", { collect, flag in self.cmdSelectDefaultCharset () })
-        parser.setEscHandler ("#8", { collect, flag in self.cmdScreenAlignmentPattern () })
-        parser.setEscHandler (" G") { collect, flags in self.cmdSet8BitControls () }
-        parser.setEscHandler (" F") { collect, flags in self.cmdSet7BitControls () }
+        parser.setEscHandler("6",   { [unowned self] collect, flag in self.columnIndex (back: true) })
+        parser.setEscHandler ("7",  { [unowned self] collect, flag in self.cmdSaveCursor ([], []) })
+        parser.setEscHandler ("8",  { [unowned self] collect, flag in self.cmdRestoreCursor ([], []) })
+        parser.setEscHandler ("9",  { [unowned self] collect, flag in self.columnIndex(back: false) })
+        parser.setEscHandler ("D",  { [unowned self] collect, flag in self.cmdIndex() })
+        parser.setEscHandler ("E",  { [unowned self] collect, flag in self.cmdNextLine () })
+        parser.setEscHandler ("H",  { [unowned self] collect, flag in self.cmdTabSet ()})
+        parser.setEscHandler ("M",  { [unowned self] collect, flag in self.reverseIndex() })
+        parser.setEscHandler ("=",  { [unowned self] collect, flag in self.cmdKeypadApplicationMode ()})
+        parser.setEscHandler (">",  { [unowned self] collect, flag in self.cmdKeypadNumericMode ()})
+        parser.setEscHandler ("c",  { [unowned self] collect, flag in self.cmdReset () })
+        parser.setEscHandler ("n",  { [unowned self] collect, flag in self.setgLevel (2) })
+        parser.setEscHandler ("o",  { [unowned self] collect, flag in self.setgLevel (3) })
+        parser.setEscHandler ("|",  { [unowned self] collect, flag in self.setgLevel (3) })
+        parser.setEscHandler ("}",  { [unowned self] collect, flag in self.setgLevel (2) })
+        parser.setEscHandler ("~",  { [unowned self] collect, flag in self.setgLevel (1) })
+        parser.setEscHandler ("%@", { [unowned self] collect, flag in self.cmdSelectDefaultCharset () })
+        parser.setEscHandler ("%G", { [unowned self] collect, flag in self.cmdSelectDefaultCharset () })
+        parser.setEscHandler ("#8", { [unowned self] collect, flag in self.cmdScreenAlignmentPattern () })
+        parser.setEscHandler (" G") { [unowned self] collect, flag in self.cmdSet8BitControls () }
+        parser.setEscHandler (" F") { [unowned self] collect, flag in self.cmdSet7BitControls () }
+        
         for bflag in CharSets.all.keys {
             let flag = String (UnicodeScalar (bflag))
             
-            parser.setEscHandler ("(" + flag, { code, f in self.selectCharset ([UInt8 (ascii: "(")] + [f]) })
-            parser.setEscHandler (")" + flag, { code, f in self.selectCharset ([UInt8 (ascii: ")")] + [f]) })
-            parser.setEscHandler ("*" + flag, { code, f in self.selectCharset ([UInt8 (ascii: "*")] + [f]) })
-            parser.setEscHandler ("+" + flag, { code, f in self.selectCharset ([UInt8 (ascii: "+")] + [f]) })
-            parser.setEscHandler ("-" + flag, { code, f in self.selectCharset ([UInt8 (ascii: "-")] + [f]) })
-            parser.setEscHandler ("." + flag, { code, f in self.selectCharset ([UInt8 (ascii: ".")] + [f]) })
-            parser.setEscHandler ("/" + flag, { code, f in self.selectCharset ([UInt8 (ascii: "/")] + [f]) })
+            parser.setEscHandler ("(" + flag, { [unowned self] code, f in self.selectCharset ([UInt8 (ascii: "(")] + [f]) })
+            parser.setEscHandler (")" + flag, { [unowned self] code, f in self.selectCharset ([UInt8 (ascii: ")")] + [f]) })
+            parser.setEscHandler ("*" + flag, { [unowned self] code, f in self.selectCharset ([UInt8 (ascii: "*")] + [f]) })
+            parser.setEscHandler ("+" + flag, { [unowned self] code, f in self.selectCharset ([UInt8 (ascii: "+")] + [f]) })
+            parser.setEscHandler ("-" + flag, { [unowned self] code, f in self.selectCharset ([UInt8 (ascii: "-")] + [f]) })
+            parser.setEscHandler ("." + flag, { [unowned self] code, f in self.selectCharset ([UInt8 (ascii: ".")] + [f]) })
+            parser.setEscHandler ("/" + flag, { [unowned self] code, f in self.selectCharset ([UInt8 (ascii: "/")] + [f]) })
         }
 
         // Error handler
-        parser.errorHandler = { state in
+        parser.errorHandler = { [unowned self] state in
             self.log ("Parsing error, state: \(state)")
             return state
         }
@@ -3619,7 +3625,7 @@ open class Terminal {
     // CSI Pm d  Vertical Position Absolute (VPA)
     //   [row] (default = [1,column])
     //
-    func cmdLinePosAbsolute (_ pars: [Int], collect: cstring)
+    func cmdLinePosAbsolute (_ pars: [Int], _ collect: cstring)
     {
         let p = max (pars.count == 0 ? 1 : pars [0], 1)
 
@@ -3668,7 +3674,7 @@ open class Terminal {
     //   xterm/charproc.c - line 2012, for more information.
     //   vim responds with ^[[?0c or ^[[?1c after the terminal's response (?)
     //
-    func cmdSendDeviceAttributes (_ pars: [Int], collect: cstring)
+    func cmdSendDeviceAttributes (_ pars: [Int], _ collect: cstring)
     {
         if pars.count > 0 && pars [0] > 0 {
             log ("SendDeviceAttributes got \(pars) and \(String(cString: collect))")
@@ -3729,7 +3735,7 @@ open class Terminal {
     //
     // CSI Ps b  Repeat the preceding graphic character Ps times (REP).
     //
-    func cmdRepeatPrecedingCharacter (_ pars: [Int], collect: cstring)
+    func cmdRepeatPrecedingCharacter (_ pars: [Int], _ collect: cstring)
     {
         // Maximum repeat, to avoid a denial of service
         let maxRepeat = cols*rows*2
@@ -3747,7 +3753,7 @@ open class Terminal {
     //  [columns] (default = [row,col+1]) (HPR)
     //reuse CSI Ps C ?
     //
-    func cmdHPositionRelative (_ pars: [Int], collect: cstring)
+    func cmdHPositionRelative (_ pars: [Int], _ collect: cstring)
     {
         let p = max (pars.count == 0 ? 1 : pars [0], 1)
         
@@ -3761,7 +3767,7 @@ open class Terminal {
     // CSI Pm `  Character Position Absolute
     //   [column] (default = [row,1]) (HPA).
     //
-    func cmdCharPosAbsolute (_ pars: [Int], collect: cstring)
+    func cmdCharPosAbsolute (_ pars: [Int], _ collect: cstring)
     {
         let p = max (pars.count == 0 ? 1 : pars [0], 1)
 
@@ -3774,7 +3780,7 @@ open class Terminal {
     //
     //CSI Ps Z  Cursor Backward Tabulation Ps tab stops (default = 1) (CBT).
     //
-    func cmdCursorBackwardTab (_ pars: [Int], collect: cstring)
+    func cmdCursorBackwardTab (_ pars: [Int], _ collect: cstring)
     {
         if buffer.x > cols {
             return
@@ -3790,7 +3796,7 @@ open class Terminal {
     // CSI Ps X
     // Erase Ps Character(s) (default = 1) (ECH).
     //
-    func cmdEraseChars (_ pars: [Int], collect: cstring)
+    func cmdEraseChars (_ pars: [Int], _ collect: cstring)
     {
         let p = max (pars.count == 0 ? 1 : pars [0], 1)
 
@@ -3800,7 +3806,7 @@ open class Terminal {
             fillData: CharData (attribute:  eraseAttr ()))
     }
 
-    func csiT (_ pars: [Int], collect: cstring)
+    func csiT (_ pars: [Int], _ collect: cstring)
     {
         if collect.count == 0 {
             cmdScrollDown(pars)
@@ -3837,7 +3843,7 @@ open class Terminal {
     //
     // CSI Ps S  Scroll up Ps lines (default = 1) (SU).
     //
-    func cmdScrollUp (_ pars: [Int], collect: cstring)
+    func cmdScrollUp (_ pars: [Int], _ collect: cstring)
     {
         let p = max (pars.count == 0 ? 1 : pars [0], 1)
         let da = CharData.defaultAttr
@@ -3874,7 +3880,7 @@ open class Terminal {
     // CSI Ps P
     // Delete Ps Character(s) (default = 1) (DCH).
     //
-    func cmdDeleteChars (pars: [Int], _ collect: cstring)
+    func cmdDeleteChars (_ pars: [Int], _ collect: cstring)
     {
         let buffer = self.buffer
         var p = max (pars.count == 0 ? 1 : pars [0], 1)

+ 1 - 2
TerminalApp/MacTerminal/AppDelegate.swift

@@ -7,12 +7,11 @@
 //
 
 import Cocoa
-
+import SwiftTerm
 @NSApplicationMain
 class AppDelegate: NSObject, NSApplicationDelegate {
     @IBOutlet var loggingMenuItem: NSMenuItem?
 
-
     func applicationDidFinishLaunching(_ aNotification: Notification) {
         // Insert code here to initialize your application
     }

+ 18 - 2
TerminalApp/MacTerminal/ViewController.swift

@@ -72,7 +72,7 @@ class ViewController: NSViewController, LocalProcessTerminalViewDelegate, NSUser
     }
     var terminal: LocalProcessTerminalView!
 
-    static var lastTerminal: LocalProcessTerminalView!
+    static weak var lastTerminal: LocalProcessTerminalView!
     
     func getBufferAsData () -> Data
     {
@@ -106,9 +106,21 @@ class ViewController: NSViewController, LocalProcessTerminalViewDelegate, NSUser
         return String (cString: pwd.pw_shell)
     }
     
+    class TD: TerminalDelegate {
+        func send(source: Terminal, data: ArraySlice<UInt8>) {
+        }
+        
+        
+    }
+
+    func test () {
+        let a = Terminal (delegate: TD ())
+        print (a)
+    }
+    
     override func viewDidLoad() {
         super.viewDidLoad()
-
+        test ()
         terminal = LocalProcessTerminalView(frame: view.frame)
         zoomGesture = NSMagnificationGestureRecognizer(target: self, action: #selector(zoomGestureHandler))
         terminal.addGestureRecognizer(zoomGesture!)
@@ -126,6 +138,10 @@ class ViewController: NSViewController, LocalProcessTerminalViewDelegate, NSUser
         updateLogging ()
     }
     
+    override func viewWillDisappear() {
+        //terminal = nil
+    }
+    
     @objc
     func zoomGestureHandler (_ sender: NSMagnificationGestureRecognizer) {
         if sender.magnification > 0 {

+ 28 - 2
Tests/SwiftTermTests/Memory.swift

@@ -11,9 +11,10 @@ import Foundation
 import XCTest
 
 @testable import SwiftTerm
+
 final class SwiftTermMemory: XCTestCase {
     static var deinited = false
-    
+    static var terminalDeinited = false
     class SimpleTerminal: HeadlessTerminal {
         
         init (queue: DispatchQueue) {
@@ -24,6 +25,31 @@ final class SwiftTermMemory: XCTestCase {
         }
     }
     
+    class EmptyTerminalDelegate: TerminalDelegate {
+        func send(source: Terminal, data: ArraySlice<UInt8>) {
+        }
+    }
+    class SubTerminal: Terminal {
+        init (delegate: TerminalDelegate) {
+            super.init(delegate: delegate)
+        }
+        
+        deinit {
+            SwiftTermMemory.terminalDeinited = true
+        }
+    }
+    
+    // This tests that the `Terminal` instance is not leaking
+    func testTerminal () {
+        SwiftTermMemory.terminalDeinited = false
+        func run () {
+            let a = SubTerminal (delegate: EmptyTerminalDelegate ())
+        }
+        run ()
+        XCTAssertEqual(SwiftTermMemory.terminalDeinited, true)
+
+    }
+    
     func allocate (){
         let queue = DispatchQueue(label: "Runner", qos: .userInteractive, attributes: .concurrent, autoreleaseFrequency: .inherit, target: nil)
         let h = SimpleTerminal(queue: queue)
@@ -32,7 +58,7 @@ final class SwiftTermMemory: XCTestCase {
     }
     
     // This test ensures that we are not keeping any strong references
-    // in the code that would prevent the terminal from being released
+    // in the code that would prevent terminal containers from being released
     func testMemory ()
     {
         SwiftTermMemory.deinited = false