Skip to content

Commit

Permalink
Merge pull request #215 from gjsify/iterators
Browse files Browse the repository at this point in the history
Inject more IterableIterator and AsyncIterableIterator types for Gtk 4 and Gio
  • Loading branch information
JumpLink authored Nov 9, 2024
2 parents 9438580 + 9bace34 commit 9b3de9d
Show file tree
Hide file tree
Showing 9 changed files with 305 additions and 64 deletions.
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@types/
75 changes: 75 additions & 0 deletions examples/gio-2-iterate/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import GLib from 'gi://GLib'
import Gio from 'gi://Gio'

Gio._promisify(Gio.File.prototype, 'enumerate_children_async', 'enumerate_children_finish')

const textDecoder = new TextDecoder('utf-8')

function readFileInChunksSync() {
// Open a file
const file = Gio.File.new_for_path('/etc/os-release')
const inputStream = file.read(null)

// Read file in chunks of 4 bytes using SyncIterator
console.log('\nReading file in chunks using SyncIterator:')
for (const bytes of inputStream.createSyncIterator(4)) {
const text = textDecoder.decode(bytes.toArray())
console.log('Chunk:', text)
}
}

async function readFileInChunksAsync() {
// Open a file
const file = Gio.File.new_for_path('/etc/os-release')
const inputStream = file.read(null)

// Read file in chunks of 4 bytes using AsyncIterator
console.log('Reading file in chunks using AsyncIterator:')
for await (const bytes of inputStream.createAsyncIterator(4)) {
const text = textDecoder.decode(bytes.toArray())
console.log('Chunk:', text)
}
}

function listDirectoryContentsSync() {
// List root directory contents synchronously
console.log('\nListing . directory contents (sync):')
const dir = Gio.File.new_for_path('.')
const enumerator = dir.enumerate_children('standard::name', Gio.FileQueryInfoFlags.NOFOLLOW_SYMLINKS, null)

for (const fileInfo of enumerator) {
console.log(fileInfo.get_name())
}
}

async function listDirectoryContentsAsync() {
// List root directory contents asynchronously
console.log('\nListing . directory contents (async):')
const dir = Gio.File.new_for_path('.')
const enumerator = await dir.enumerate_children_async(
'standard::name',
Gio.FileQueryInfoFlags.NOFOLLOW_SYMLINKS,
GLib.PRIORITY_DEFAULT,
null,
)

for await (const file_info of enumerator) {
console.log(file_info.get_name())
}
}

// Run all examples
const loop = new GLib.MainLoop(null, false)

const start = async () => {
readFileInChunksSync()
listDirectoryContentsSync()
await readFileInChunksAsync()
await listDirectoryContentsAsync()
}

start().then(() => {
loop.quit()
})

loop.run()
24 changes: 24 additions & 0 deletions examples/gio-2-iterate/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"name": "@ts-for-gir-example/gio-2-iterate",
"version": "4.0.0-beta.18",
"description": "Example demonstrating GIO async and sync iterators",
"type": "module",
"private": true,
"scripts": {
"build:app": "tsc",
"build": "yarn build:app",
"start:app": "gjs -m dist/main.js",
"start": "yarn build && yarn start:app",
"validate": "yarn validate:types",
"validate:types": "tsc --noEmit",
"clear": "rm -rf dist"
},
"devDependencies": {
"typescript": "^5.6.3"
},
"dependencies": {
"@girs/gio-2.0": "workspace:^",
"@girs/gjs": "workspace:^",
"@girs/glib-2.0": "workspace:^"
}
}
18 changes: 18 additions & 0 deletions examples/gio-2-iterate/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"compilerOptions": {
"lib": ["ESNext"],
"types": ["@girs/gjs", "@girs/gjs/dom", "@girs/glib-2.0", "@girs/gio-2.0"],
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"noImplicitThis": true,
"alwaysStrict": true,
"outDir": "./dist"
},
"files": [
"main.ts"
]
}
122 changes: 58 additions & 64 deletions examples/gio-2-list-model/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,76 +3,75 @@
* SPDX-FileCopyrightText: 2020 Andy Holmes <[email protected]>
* @source https://gitlab.gnome.org/GNOME/gjs/-/blob/master/examples/glistmodel.js
*/
import GObject from 'gi://GObject?version=2.0';
import Gio from 'gi://Gio?version=2.0';
import GObject from 'gi://GObject?version=2.0'
import Gio from 'gi://Gio?version=2.0'

/**
* An example of implementing the GListModel interface in GJS. The only real
* requirement here is that the class be derived from some GObject.
*/
export class IGjsListStore extends GObject.Object implements Gio.ListModel {

_items: GObject.Object[] = [];
_items: GObject.Object[] = []

_init() {
super._init();
super._init()

/* We'll use a native Array as internal storage for the list model */
this._items = [];
this._items = []
}

// TODO: It should not be necessary to implement this method
get_item_type() {
const res = GObject.Object.$gtype;
print("get_item_type", res);
return res;
const res = GObject.Object.$gtype
print('get_item_type', res)
return res
}

// TODO: It should not be necessary to implement this method
get_item(position: number) {
const res = this._items[position] || null;
print("get_item", res);
return res;
const res = this._items[position] || null
print('get_item', res)
return res
}

// TODO: It should not be necessary to implement this method
items_changed(position: number, removed: number, added: number) {
print(`items_changed position: ${position}, removed: ${removed}, added: ${added}`);
print(`items_changed position: ${position}, removed: ${removed}, added: ${added}`)
}

// TODO: It should not be necessary to implement this method
get_n_items() {
const res = this._items.length;
print("get_n_items", res);
return res;
const res = this._items.length
print('get_n_items', res)
return res
}

/* Implementing this function amounts to returning a GType. This could be a
* more specific GType, but must be a subclass of GObject.
*/
vfunc_get_item_type() {
const res = GObject.Object.$gtype;
print("vfunc_get_item_type", res);
return res;
const res = GObject.Object.$gtype
print('vfunc_get_item_type', res)
return res
}

/* Implementing this function just requires returning the GObject at
* @position or %null if out-of-range. This must explicitly return %null,
* not `undefined`.
*/
vfunc_get_item(position: number) {
const res = this._items[position] || null;
print("vfunc_get_item", res);
return res;
const res = this._items[position] || null
print('vfunc_get_item', res)
return res
}

/* Implementing this function is as simple as return the length of the
* storage object, in this case an Array.
*/
vfunc_get_n_items() {
const res = this._items.length;
print("vfunc_get_n_items", res);
return res;
const res = this._items.length
print('vfunc_get_n_items', res)
return res
}

/**
Expand All @@ -84,14 +83,12 @@ export class IGjsListStore extends GObject.Object implements Gio.ListModel {
* @param position - the position to add the item
*/
insertItem(item: GObject.Object, position: number) {
if (!(item instanceof GObject.Object))
throw new TypeError('not a GObject');
if (!(item instanceof GObject.Object)) throw new TypeError('not a GObject')

if (position < 0 || position > this._items.length)
position = this._items.length;
if (position < 0 || position > this._items.length) position = this._items.length

this._items.splice(position, 0, item);
this.items_changed(position, 0, 1);
this._items.splice(position, 0, item)
this.items_changed(position, 0, 1)
}

/**
Expand All @@ -100,13 +97,12 @@ export class IGjsListStore extends GObject.Object implements Gio.ListModel {
* @param item - the item to add
*/
appendItem(item: GObject.Object) {
if (!(item instanceof GObject.Object))
throw new TypeError('not a GObject');
if (!(item instanceof GObject.Object)) throw new TypeError('not a GObject')

let position = this._items.length;
let position = this._items.length

this._items.push(item);
this.items_changed(position, 0, 1);
this._items.push(item)
this.items_changed(position, 0, 1)
}

/**
Expand All @@ -115,11 +111,10 @@ export class IGjsListStore extends GObject.Object implements Gio.ListModel {
* @param item - the item to add
*/
prependItem(item: GObject.Object) {
if (!(item instanceof GObject.Object))
throw new TypeError('not a GObject');
if (!(item instanceof GObject.Object)) throw new TypeError('not a GObject')

this._items.unshift(item);
this.items_changed(0, 0, 1);
this._items.unshift(item)
this.items_changed(0, 0, 1)
}

/**
Expand All @@ -129,16 +124,14 @@ export class IGjsListStore extends GObject.Object implements Gio.ListModel {
* @param item - the item to remove
*/
removeItem(item: GObject.Object) {
if (!(item instanceof GObject.Object))
throw new TypeError('not a GObject');
if (!(item instanceof GObject.Object)) throw new TypeError('not a GObject')

let position = this._items.indexOf(item);
let position = this._items.indexOf(item)

if (position === -1)
return;
if (position === -1) return

this._items.splice(position, 1);
this.items_changed(position, 1, 0);
this._items.splice(position, 1)
this.items_changed(position, 1, 0)
}

/**
Expand All @@ -148,36 +141,37 @@ export class IGjsListStore extends GObject.Object implements Gio.ListModel {
* @param position - the position of the item to remove
*/
removePosition(position: number) {
if (position < 0 || position >= this._items.length)
return;
if (position < 0 || position >= this._items.length) return

this._items.splice(position, 1);
this.items_changed(position, 1, 0);
this._items.splice(position, 1)
this.items_changed(position, 1, 0)
}

/**
* Clear the list of all items.
*/
clear() {
let length = this._items.length;
let length = this._items.length

if (length === 0)
return;
if (length === 0) return

this._items = [];
this.items_changed(0, length, 0);
this._items = []
this.items_changed(0, length, 0)
}
}

/**
* An example of implementing the GListModel interface in GJS. The only real
* requirement here is that the class be derived from some GObject.
*/
export const GjsListStore = GObject.registerClass({
GTypeName: 'GjsListStore',
Implements: [Gio.ListModel],
}, IGjsListStore);

// TODO: Expand the example which also demonstrates the use of the listStore
const listStore = new GjsListStore();
listStore.insertItem(new GObject.Object(), 0);
export const GjsListStore = GObject.registerClass(
{
GTypeName: 'GjsListStore',
Implements: [Gio.ListModel],
},
IGjsListStore,
)

// TODO: Expand the example which also demonstrates the use of the listStore
const listStore = new GjsListStore()
listStore.insertItem(new GObject.Object(), 0)
Loading

0 comments on commit 9b3de9d

Please sign in to comment.