@@ -5,6 +5,7 @@ const Clutter = imports.gi.Clutter;
55const Cogl = imports . gi . Cogl ;
66const Gio = imports . gi . Gio ;
77const GLib = imports . gi . GLib ;
8+ const GObject = imports . gi . GObject ;
89const Lang = imports . lang ;
910const Meta = imports . gi . Meta ;
1011const Signals = imports . signals ;
@@ -36,13 +37,94 @@ var commandHeader = 'const Clutter = imports.gi.Clutter; ' +
3637 'const r = Lang.bind(Main.lookingGlass, Main.lookingGlass.getResult); ' ;
3738
3839const HISTORY_KEY = 'looking-glass-history' ;
39- function objectToString ( o ) {
40- if ( typeof ( o ) == typeof ( objectToString ) ) {
41- // special case this since the default is way, way too verbose
42- return '<js function>' ;
40+
41+ /* fake types for special cases:
42+ * -"array": objects that pass Array.isArray() and should only show enumerable properties
43+ * -"importer": objects that load modules on property access
44+ */
45+
46+ // returns [typeString, valueString] for any object
47+ function getObjInfo ( o ) {
48+ let type , value ;
49+ if ( o === null )
50+ type = "null" ;
51+ else if ( o === undefined )
52+ type = "undefined" ;
53+
54+ if ( type ) {
55+ value = "[" + type + "]" ;
4356 } else {
44- return '' + o ;
57+ // try to detect importers via their string representation
58+ try {
59+ value = o . toString ( ) ;
60+ } catch ( e ) {
61+ if ( e . message . includes ( "not an object instance - cannot convert to GObject*" ) ) {
62+ // work around Clutter.Actor.prototype.toString override not handling being
63+ // called with the prototype itself as 'this'
64+ value = GObject . Object . prototype . toString . call ( o ) ;
65+ } else {
66+ value = "[error getting value]" ;
67+ }
68+ }
69+
70+ if ( value . startsWith ( "[GjsFileImporter" )
71+ || value . startsWith ( "[object GjsModule gi" ) ) {
72+ type = "importer" ;
73+ } else if ( Array . isArray ( o ) ) {
74+ type = "array" ;
75+ } else {
76+ type = typeof ( o ) ;
77+ }
78+
79+ // make empty strings/arrays obvious
80+ if ( value === "" )
81+ value = "[empty]" ;
82+ }
83+
84+ return [ type , value ] ;
85+ }
86+
87+ // returns an array of dictionaries conforming to the Inspect dbus schema
88+ function getObjKeysInfo ( obj ) {
89+ let [ type , ] = getObjInfo ( obj ) ;
90+ if ( ! [ "array" , "object" ] . includes ( type ) )
91+ return [ ] ;
92+
93+ let keys = new Set ( ) ;
94+ let curProto = obj ;
95+
96+ // we ignore the Object prototype
97+ while ( curProto && curProto !== Object . prototype ) {
98+ let ownKeys ;
99+ if ( type === "array" )
100+ ownKeys = curProto . keys ( ) ; // index properties only
101+ else
102+ ownKeys = Reflect . ownKeys ( curProto ) ; // all own properties and symbols
103+
104+ // adding to set ignores duplicates
105+ for ( let key of ownKeys )
106+ keys . add ( key ) ;
107+
108+ curProto = Object . getPrototypeOf ( curProto ) ;
109+ }
110+
111+
112+ return Array . from ( keys ) . map ( ( k ) => {
113+ let [ t , v ] = getObjInfo ( obj [ k ] ) ;
114+ return { name : k . toString ( ) , type : t , value : v , shortValue : "" } ;
115+ } ) ;
116+ }
117+
118+ // always returns an object we can give back to melange.
119+ // it may be useful to inspect Error() objects
120+ function tryEval ( js ) {
121+ let out ;
122+ try {
123+ out = eval ( js ) ;
124+ } catch ( e ) {
125+ out = e ;
45126 }
127+ return out ;
46128}
47129
48130function WindowList ( ) {
@@ -93,13 +175,13 @@ WindowList.prototype = {
93175
94176 let lgInfo = {
95177 id : metaWindow . _lgId . toString ( ) ,
96- title : objectToString ( metaWindow . title ) ,
97- wmclass : objectToString ( metaWindow . get_wm_class ( ) ) ,
178+ title : metaWindow . title + '' ,
179+ wmclass : metaWindow . get_wm_class ( ) + '' ,
98180 app : '' } ;
99181
100182 let app = tracker . get_window_app ( metaWindow ) ;
101183 if ( app != null && ! app . is_window_backed ( ) ) {
102- lgInfo . app = objectToString ( app . get_id ( ) ) ;
184+ lgInfo . app = app . get_id ( ) + '' ;
103185 } else {
104186 lgInfo . app = '<untracked>' ;
105187 }
@@ -454,43 +536,18 @@ Melange.prototype = {
454536 _pushResult : function ( command , obj , tooltip ) {
455537 let index = this . _results . length ;
456538 let result = { "o" : obj , "index" : index } ;
457- this . rawResults . push ( { command : command , type : typeof ( obj ) , object : objectToString ( obj ) , index : index . toString ( ) , tooltip : tooltip } ) ;
539+ let [ type , value ] = getObjInfo ( obj ) ;
540+ this . rawResults . push ( { command : command , type : type , object : value , index : index . toString ( ) , tooltip : tooltip } ) ;
458541 this . emitResultUpdate ( ) ;
459-
542+
460543 this . _results . push ( result ) ;
461544 this . _it = obj ;
462545 } ,
463546
464547 inspect : function ( path ) {
465548 let fullCmd = commandHeader + path ;
466-
467- let result = eval ( fullCmd ) ;
468- let resultObj = [ ] ;
469- for ( let key in result ) {
470- let type = typeof ( result [ key ] ) ;
471-
472- //fixme: move this shortvalue stuff to python lg
473- let shortValue , value ;
474- if ( type === "undefined" ) {
475- value = "" ;
476- shortValue = "" ;
477- } else if ( result [ key ] === null ) {
478- value = "[null]" ;
479- shortValue = value ;
480- } else {
481- value = result [ key ] . toString ( ) ;
482- shortValue = value ;
483- let i = value . indexOf ( '\n' ) ;
484- let j = value . indexOf ( '\r' ) ;
485- if ( j != - 1 && ( i == - 1 || i > j ) )
486- i = j ;
487- if ( i != - 1 )
488- shortValue = value . substr ( 0 , i ) + '.. <more>' ;
489- }
490- resultObj . push ( { name : key , type : type , value : value , shortValue : shortValue } ) ;
491- }
492-
493- return resultObj ;
549+ let result = tryEval ( fullCmd ) ;
550+ return getObjKeysInfo ( result ) ;
494551 } ,
495552
496553 getIt : function ( ) {
@@ -519,24 +576,14 @@ Melange.prototype = {
519576 this . _history . addItem ( command ) ;
520577
521578 let fullCmd = commandHeader + command ;
522-
523- let resultObj ;
524-
525579 let ts = GLib . get_monotonic_time ( ) ;
526580
527- try {
528- resultObj = eval ( fullCmd ) ;
529- } catch ( e ) {
530- resultObj = '<exception ' + e + '>' ;
531- }
581+ let resultObj = tryEval ( fullCmd ) ;
532582
533583 let ts2 = GLib . get_monotonic_time ( ) ;
534-
535584 let tooltip = _ ( "Execution time (ms): " ) + ( ts2 - ts ) / 1000 ;
536585
537586 this . _pushResult ( command , resultObj , tooltip ) ;
538-
539- return ;
540587 } ,
541588
542589 // DBus function
@@ -547,14 +594,7 @@ Melange.prototype = {
547594 // DBus function
548595 AddResult : function ( path ) {
549596 let fullCmd = commandHeader + path ;
550-
551- let resultObj ;
552- try {
553- resultObj = eval ( fullCmd ) ;
554- } catch ( e ) {
555- resultObj = '<exception ' + e + '>' ;
556- }
557- this . _pushResult ( path , resultObj , "" ) ;
597+ this . _pushResult ( path , tryEval ( fullCmd ) , "" ) ;
558598 } ,
559599
560600 // DBus function
0 commit comments