Skip to content

Commit 0d67ce6

Browse files
committed
v0.2.0 with new algorithm
1 parent 0e1eeb5 commit 0d67ce6

File tree

9 files changed

+1967
-1621
lines changed

9 files changed

+1967
-1621
lines changed

README.md

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ Check it out at [matrix-notepad.kb1rd.net](https://matrix-notepad.kb1rd.net/) an
77
This is not in any particular order:
88
* [x] More or less working insertions
99
* [x] More or less working removals
10-
* [ ] Conflict resolution
11-
* [ ] Improved UI/UX (this will be incremental)
10+
* [ ] Conflict resolution -- Almost!
11+
* [x] Improved UI/UX (this will be incremental)
1212
* [ ] Unit testing!!!
13-
* [ ] Create a different package for the `Logootish` algorithm
13+
* [x] Create a different package for the `Logootish` algorithm -- Right [here](https://github.com/KB1RD/logootish-js)
1414
* [ ] Node 'squashing' or similar. Currently Matrix Notepad has to sync ALL of the events :(
1515
* [ ] Rich text editing
1616

@@ -23,9 +23,7 @@ Fundementally, it is frustrating that there is no standard way to collaborate on
2323
Just head on over to [matrix-notepad.kb1rd.net](https://matrix-notepad.kb1rd.net/) and sign in. This will bring you to a room list. It's not a great idea to re-use rooms, so if you haven't joined a document room yet, click the "Add" button at the top of the room list and either create a room or join an existing one by ID or alias.
2424

2525
### WARNING!
26-
First of all, since this is experimental software, do not use it to store very important or confidential information. Second, I have recommended to some of the Matrix devs that they create another account to test this program. This program *shouldn't* do anything to break anyone's account -- I use it on my normal Matrix account and nothing bad has happened. Yet. I suggested that they use another account because their job depends upon a working account. If you *absolutely* need your Matrix account every day, I would recommend creating another account just to be safe. This program will:
27-
1.) Post a good number of events to whichever room you choose. If you use this to type out a novel or something, it may slow down Riot since sync requests get larger, but this shouldn't be too much of an issue
28-
2.) Scroll back as far as possible in whichever room you choose. For this reason, **do not** open public chats since the editor will try to sync back to the beginning of time and probably crash your browser. I'm working on a more efficient sync system. See issue #11
26+
Since this is experimental software, do not use it to store very important or confidential information. I am not responsible for lost information
2927

3028
### Bug Reporting
3129
If you see error messages pop up or you encounter any bugs, **please** report it either on GitHub or on the Matrix chat. This is **very** helpful as I'm sure there are bugs that I don't know about.
@@ -40,20 +38,29 @@ Have a look at the [Wiki](https://github.com/KB1RD/matrix-notepad/wiki) if you'r
4038

4139
## Organization
4240
Here is the directory structure
43-
* `algorithms` -- A directory for possible algorithms in case I ever want to develop others. This is more of an organizational thing
44-
* `/logootish` -- The `logootish` algorithm that I developed. This is the more interesting of all the directories
45-
* `/index.js` -- The main Logootish algorithm
46-
* `/bst.js` -- A custom binary sorting tree that supports custom compare functions and supports getting groups of nodes. This is used to select regions of nodes to consider. This may need a rewrite
47-
* `/ints.js` -- A custom `Int32` type. I implemented this so that any int-based type would have a standard interface using methods rather than operators because JavaScript doesn't support operator overloading. In the future, it would be possible to replace the `Int32` type with any other int type because of this interface. Because it's only an Int32, the document will have issues if you add 2^31 characters consecutively, but then again so will most web browsers :)
48-
* `utils.js` -- Random utilities that I should move somewhere else. This includes `Enum`, `arraymap`, `PeekableIterator`, and `FatalError`
4941
* `components` -- Vue components
5042
* `layouts` -- Nuxt layouts. This is currently just the default layout
5143
* `pages` -- Nuxt pages
5244
* `plugins` -- Nuxt plugins that perform vital functions for the program that are not the algorithm or the Vuex store
45+
* `/matrix.js` -- Provides the interface between Matrix, the GUI, and the algorithm. It is dense and poorly written since I'm still trying to figure out where to put everything.
5346
* `static` -- Static files. Currently only has the site icon
5447
* `store` -- The Vuex store. This is used for UI only since I want the algorithm to be seperate from Vue.JS. Vuex does track the state of the Matrix client, but not the state of document nodes (that's all "traditional" ES6 JS)
5548
* `test` -- A directory that I have reserved for unit testing. This would help **a lot** if I actually implemented it. *sigh*
5649

50+
## Debugging
51+
I have removed the debug panel as of version `0.2.0` in favor of a console based debug under the window-scope variable `$debug`. Here's the main tricks:
52+
53+
```js
54+
// Provides direct access to the ListDocumentModel
55+
$debug.active_document.ldm
56+
57+
// Disable the initial load
58+
$debug.syncback_settings.initial = false
59+
60+
// Manually fetch events (if initial load is disabled)
61+
$debug.active_document.fetchEvents(1)
62+
```
63+
5764
## Build Setup
5865
``` bash
5966
# install dependencies

components/DebugPanel.vue

Lines changed: 0 additions & 93 deletions
This file was deleted.

components/DocumentEditor.vue

Lines changed: 38 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
style="text-align: left; margin: -24px -32px; margin-top: 3em; overflow: auto;"
1616
:options="cmOption"
1717
@ready="$emit('ready')"
18-
@changes="onNewChanges"
18+
@beforeChange="onNewChanges"
1919
/>
2020
</client-only>
2121
</a-card>
@@ -32,6 +32,7 @@ export default {
3232
3333
data() {
3434
return {
35+
console,
3536
text: '',
3637
3738
cmOption: {
@@ -73,63 +74,52 @@ export default {
7374
7475
cmdoc.replaceRange('', startpos, endpos)
7576
},
77+
translate(src, dest, len) {
78+
const cmdoc = this.$refs.codemirror.codemirror.doc
79+
debug.log(`TRANSLATE ${len} CHARS FROM ${src} -> ${dest}`)
80+
const startpos = cmdoc.posFromIndex(src)
81+
const endpos = cmdoc.posFromIndex(src + len)
82+
const body = cmdoc.getRange(startpos, endpos)
83+
this.remove(src, len)
84+
this.insert(dest, body)
85+
},
7686
77-
onNewChanges(cm, changes) {
87+
onNewChanges(cm, change) {
7888
const line_seperator = '\n'
79-
const modifyCmLinePositionBasedOnText = (to, text) => {
80-
// Add the extra lines in to the line count
81-
to.line += text.length - 1
82-
// If there's a new line, go back to the start of the line
83-
if (text.length > 1) {
84-
to.ch = 0
89+
// TODO: Possible create a custom CM document to fix this BS. That way,
90+
// text appears as part of the local echo of a Matrix event
91+
if (
92+
this.changes_to_ignore[change.from.line] &&
93+
this.changes_to_ignore[change.from.line].includes(change.from.ch)
94+
) {
95+
this.changes_to_ignore[change.from.line].pop(change.from.ch)
96+
if (!this.changes_to_ignore[change.from.line].length) {
97+
delete this.changes_to_ignore[change.from.line]
8598
}
86-
// Add the final line position
87-
to.ch += text[text.length - 1].length
88-
89-
return to
99+
return
90100
}
91101
92-
changes.forEach((change) => {
93-
// TODO: Possible create a custom CM document to fix this BS. That way,
94-
// text appears as part of the local echo of a Matrix event
95-
if (
96-
this.changes_to_ignore[change.from.line] &&
97-
this.changes_to_ignore[change.from.line].includes(change.from.ch)
98-
) {
99-
this.changes_to_ignore[change.from.line].pop(change.from.ch)
100-
if (!this.changes_to_ignore[change.from.line].length) {
101-
delete this.changes_to_ignore[change.from.line]
102-
}
103-
return
104-
}
105-
106-
const from = Object.assign({}, change.from)
107-
const from_index = cm.indexFromPos(from)
102+
// Local echos will replay the change
103+
change.cancel()
108104
109-
// Addition is in the post-removal coordinate system
110-
const addition_to = Object.assign({}, change.from)
105+
const from = Object.assign({}, change.from)
106+
const from_index = cm.indexFromPos(from)
107+
const to = Object.assign({}, change.to)
108+
const to_index = cm.indexFromPos(to)
111109
112-
// Update based on actual values (in my experience, CM reports incorrect
113-
// lengths in *some* cases, so this just starts from scratch)
114-
modifyCmLinePositionBasedOnText(addition_to, change.text)
110+
// Length of removal
111+
const removal_length = to_index - from_index
115112
116-
// Length of removal. Start w/ the newline chars:
117-
let removal_length = change.removed.length - 1
118-
change.removed.forEach((str) => {
119-
removal_length += str.length
120-
})
113+
// Raw text of the addition
114+
const addition_raw = change.text.join(line_seperator)
121115
122-
// Raw text of the addition
123-
const addition_raw = change.text.join(line_seperator)
124-
125-
if (removal_length) {
126-
this.$emit('remove', { pos: from_index, length: removal_length })
127-
}
116+
if (removal_length) {
117+
this.$emit('remove', { pos: from_index, length: removal_length })
118+
}
128119
129-
if (addition_raw.length) {
130-
this.$emit('insert', { pos: from_index, body: addition_raw })
131-
}
132-
})
120+
if (addition_raw.length) {
121+
this.$emit('insert', { pos: from_index, body: addition_raw })
122+
}
133123
}
134124
}
135125
}

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "matrix-notepad",
3-
"version": "0.1.7",
3+
"version": "0.2.0",
44
"description": "Store & collaborate on text files over the Matrix protocol",
55
"author": "Nathan Pennie",
66
"license": "GPL-3.0",
@@ -17,6 +17,7 @@
1717
"@nuxtjs/axios": "^5.3.6",
1818
"ant-design-vue": "^1.1.10",
1919
"codemirror": "^5.48.2",
20+
"jsonschema": "^1.2.5",
2021
"logootish-js": "https://github.com/KB1RD/logootish-js.git#v0.2.1",
2122
"matrix-js-sdk": "^2.3.0",
2223
"nuxt": "^2.0.0",

pages/edit/_room.vue

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,6 @@
1111
WIP
1212
</a-drawer> -->
1313

14-
<DebugPanel
15-
v-if="$store.state.debug"
16-
cansync
17-
@fetch="(n) => (fetchEvents ? fetchEvents(n) : undefined)"
18-
@dumpLogoot="dumpLogoot"
19-
@dumpLdoc="dumpLdoc"
20-
@dumpRemoval="dumpRemoval"
21-
/>
22-
2314
<div style="margin: 10px 0px; text-align: left;">
2415
<a-button type="primary" icon="home" @click="$router.push('/')">
2516
Home
@@ -46,15 +37,14 @@
4637

4738
<script>
4839
import { debug } from '@/plugins/debug'
49-
import DebugPanel from '@/components/DebugPanel'
5040
import DocumentEditor from '@/components/DocumentEditor'
5141
5242
export default {
5343
validate({ params }) {
5444
return /^[!#][^!#:]*:[^!#:]*(:[0-9]+)?$/gm.test(params.room)
5545
},
5646
57-
components: { DebugPanel, DocumentEditor },
47+
components: { DocumentEditor },
5848
5949
head() {
6050
return {
@@ -112,14 +102,31 @@ export default {
112102
self.cm_resolve_ready = resolve
113103
}
114104
})
105+
const onOperation = (ops) => {
106+
ops.forEach((op) => {
107+
switch (op.type) {
108+
case 'i':
109+
this.$refs.editor.insert(op.start, op.body)
110+
return
111+
case 'r':
112+
this.$refs.editor.remove(op.start, op.length)
113+
return
114+
case 't':
115+
this.$refs.editor.translate(op.source, op.dest, op.length)
116+
}
117+
})
118+
}
115119
const doc = await self.$matrix.createDocument(
116120
this.$route.params.room,
117-
this.$refs.editor.insert,
118-
this.$refs.editor.remove,
121+
onOperation,
119122
this.onDocumentError
120123
)
121124
125+
// The old debug panel has been replaced in favor of this
126+
this.$debug.active_document = doc
127+
122128
// This is a really stupid way to keep the document out of Vue's reach
129+
// (We do **not** want Vue doing state tracking on the CRDT)
123130
Object.defineProperty(this, 'document', {
124131
get() {
125132
return doc
@@ -169,17 +176,17 @@ export default {
169176
170177
dumpLogoot() {
171178
if (this.document) {
172-
debug.info(this.document.logoot_bst.toString())
179+
debug.info(this.document.doc.logoot_bst.toString())
173180
}
174181
},
175182
dumpLdoc() {
176183
if (this.document) {
177-
debug.info(this.document.ldoc_bst.toString())
184+
debug.info(this.document.doc.ldoc_bst.toString())
178185
}
179186
},
180187
dumpRemoval() {
181188
if (this.document) {
182-
debug.info(this.document.removal_bst.toString())
189+
debug.info(this.document.doc.removal_bst.toString())
183190
}
184191
}
185192

pages/index.vue

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
<template>
22
<div class="container">
33
<div>
4-
<DebugPanel v-if="$store.state.debug" />
5-
64
<a-button
75
type="dashed"
86
block
@@ -35,11 +33,10 @@
3533
</template>
3634

3735
<script>
38-
import DebugPanel from '@/components/DebugPanel'
3936
import AddRoomModal from '@/components/AddRoomModal'
4037
4138
export default {
42-
components: { DebugPanel, AddRoomModal },
39+
components: { AddRoomModal },
4340
4441
computed: {
4542
rooms() {

0 commit comments

Comments
 (0)