First rought implementation of conflicts resolution view

This commit is contained in:
Silvano Cerza 2025-02-13 14:43:46 +01:00
parent c0792c79e7
commit f409216320
7 changed files with 670 additions and 12 deletions

View file

@ -24,6 +24,10 @@
"typescript": "^5.7.2"
},
"dependencies": {
"@codemirror/lang-markdown": "^6.3.2",
"@codemirror/state": "^6.5.2",
"@codemirror/view": "^6.36.2",
"codemirror": "^6.0.1",
"react": "^19.0.0",
"react-dom": "^19.0.0"
}

View file

@ -8,6 +8,18 @@ importers:
.:
dependencies:
'@codemirror/lang-markdown':
specifier: ^6.3.2
version: 6.3.2
'@codemirror/state':
specifier: ^6.5.2
version: 6.5.2
'@codemirror/view':
specifier: ^6.36.2
version: 6.36.2
codemirror:
specifier: ^6.0.1
version: 6.0.1
react:
specifier: ^19.0.0
version: 19.0.0
@ -38,7 +50,7 @@ importers:
version: 0.24.2
obsidian:
specifier: ^1.7.2
version: 1.7.2(@codemirror/state@6.5.0)(@codemirror/view@6.36.1)
version: 1.7.2(@codemirror/state@6.5.2)(@codemirror/view@6.36.2)
tslib:
specifier: ^2.8.1
version: 2.8.1
@ -48,11 +60,46 @@ importers:
packages:
'@codemirror/state@6.5.0':
resolution: {integrity: sha512-MwBHVK60IiIHDcoMet78lxt6iw5gJOGSbNbOIVBHWVXIH4/Nq1+GQgLLGgI1KlnN86WDXsPudVaqYHKBIx7Eyw==}
'@babel/code-frame@7.26.2':
resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==}
engines: {node: '>=6.9.0'}
'@codemirror/view@6.36.1':
resolution: {integrity: sha512-miD1nyT4m4uopZaDdO2uXU/LLHliKNYL9kB1C1wJHrunHLm/rpkb5QVSokqgw9hFqEZakrdlb/VGWX8aYZTslQ==}
'@babel/helper-validator-identifier@7.25.9':
resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==}
engines: {node: '>=6.9.0'}
'@codemirror/autocomplete@6.18.6':
resolution: {integrity: sha512-PHHBXFomUs5DF+9tCOM/UoW6XQ4R44lLNNhRaW9PKPTU0D7lIjRg3ElxaJnTwsl/oHiR93WSXDBrekhoUGCPtg==}
'@codemirror/commands@6.8.0':
resolution: {integrity: sha512-q8VPEFaEP4ikSlt6ZxjB3zW72+7osfAYW9i8Zu943uqbKuz6utc1+F170hyLUCUltXORjQXRyYQNfkckzA/bPQ==}
'@codemirror/lang-css@6.3.1':
resolution: {integrity: sha512-kr5fwBGiGtmz6l0LSJIbno9QrifNMUusivHbnA1H6Dmqy4HZFte3UAICix1VuKo0lMPKQr2rqB+0BkKi/S3Ejg==}
'@codemirror/lang-html@6.4.9':
resolution: {integrity: sha512-aQv37pIMSlueybId/2PVSP6NPnmurFDVmZwzc7jszd2KAF8qd4VBbvNYPXWQq90WIARjsdVkPbw29pszmHws3Q==}
'@codemirror/lang-javascript@6.2.3':
resolution: {integrity: sha512-8PR3vIWg7pSu7ur8A07pGiYHgy3hHj+mRYRCSG8q+mPIrl0F02rgpGv+DsQTHRTc30rydOsf5PZ7yjKFg2Ackw==}
'@codemirror/lang-markdown@6.3.2':
resolution: {integrity: sha512-c/5MYinGbFxYl4itE9q/rgN/sMTjOr8XL5OWnC+EaRMLfCbVUmmubTJfdgpfcSS2SCaT7b+Q+xi3l6CgoE+BsA==}
'@codemirror/language@6.10.8':
resolution: {integrity: sha512-wcP8XPPhDH2vTqf181U8MbZnW+tDyPYy0UzVOa+oHORjyT+mhhom9vBd7dApJwoDz9Nb/a8kHjJIsuA/t8vNFw==}
'@codemirror/lint@6.8.4':
resolution: {integrity: sha512-u4q7PnZlJUojeRe8FJa/njJcMctISGgPQ4PnWsd9268R4ZTtU+tfFYmwkBvgcrK2+QQ8tYFVALVb5fVJykKc5A==}
'@codemirror/search@6.5.9':
resolution: {integrity: sha512-7DdQ9aaZMMxuWB1u6IIFWWuK9NocVZwvo4nG8QjJTS6oZGvteoLSiXw3EbVZVlO08Ri2ltO89JVInMpfcJxhtg==}
'@codemirror/state@6.5.2':
resolution: {integrity: sha512-FVqsPqtPWKVVL3dPSxy8wEF/ymIEuVzF1PK3VbUgrxXpJUSHQWWZz4JMToquRxnkw+36LTamCZG2iua2Ptq0fA==}
'@codemirror/view@6.36.2':
resolution: {integrity: sha512-DZ6ONbs8qdJK0fdN7AB82CgI6tYXf4HWk1wSVa0+9bhVznCuuvhQtX8bFBoy3dv8rZSQqUd8GvhVAcielcidrA==}
'@esbuild/aix-ppc64@0.24.2':
resolution: {integrity: sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==}
@ -258,6 +305,33 @@ packages:
resolution: {integrity: sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==}
engines: {node: '>=18.18'}
'@jridgewell/sourcemap-codec@1.5.0':
resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==}
'@lezer/common@1.2.3':
resolution: {integrity: sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA==}
'@lezer/css@1.1.10':
resolution: {integrity: sha512-V5/89eDapjeAkWPBpWEfQjZ1Hag3aYUUJOL8213X0dFRuXJ4BXa5NKl9USzOnaLod4AOpmVCkduir2oKwZYZtg==}
'@lezer/highlight@1.2.1':
resolution: {integrity: sha512-Z5duk4RN/3zuVO7Jq0pGLJ3qynpxUVsh7IbUbGj88+uV2ApSAn6kWg2au3iJb+0Zi7kKtqffIESgNcRXWZWmSA==}
'@lezer/html@1.3.10':
resolution: {integrity: sha512-dqpT8nISx/p9Do3AchvYGV3qYc4/rKr3IBZxlHmpIKam56P47RSHkSF5f13Vu9hebS1jM0HmtJIwLbWz1VIY6w==}
'@lezer/javascript@1.4.21':
resolution: {integrity: sha512-lL+1fcuxWYPURMM/oFZLEDm0XuLN128QPV+VuGtKpeaOGdcl9F2LYC3nh1S9LkPqx9M0mndZFdXCipNAZpzIkQ==}
'@lezer/lr@1.4.2':
resolution: {integrity: sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA==}
'@lezer/markdown@1.4.1':
resolution: {integrity: sha512-Za5okfyWoNaX6sSZ2dm94XegaFXbkQ9UjKJ8hAoZX88XDpbu6DoR63IuSl+dqj1VkVQBQGsdr0JnTcMsogQDdw==}
'@marijn/buildtool@0.1.6':
resolution: {integrity: sha512-rcA2wljsM24MFAwx2U5vSBrt7IdIaPh4WPRfJPS8PuCUlbuQ8Pmky4c/ec00v3YFu90rZSbkVLnPuCeb/mUEng==}
'@marijn/find-cluster-break@1.0.2':
resolution: {integrity: sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==}
@ -282,6 +356,9 @@ packages:
'@types/json-schema@7.0.15':
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
'@types/mocha@9.1.1':
resolution: {integrity: sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw==}
'@types/node@22.10.5':
resolution: {integrity: sha512-F8Q+SeGimwOo86fiovQh8qiXfFEh2/ocYv7tU5pJ3EXMSSxk1Joj5wefpFK2fHTf/N6HKGSxIDBT9f3gCxXPkQ==}
@ -348,6 +425,10 @@ packages:
peerDependencies:
acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
acorn-walk@8.3.4:
resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==}
engines: {node: '>=0.4.0'}
acorn@8.14.0:
resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==}
engines: {node: '>=0.4.0'}
@ -388,6 +469,9 @@ packages:
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
engines: {node: '>=10'}
codemirror@6.0.1:
resolution: {integrity: sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==}
color-convert@2.0.1:
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
engines: {node: '>=7.0.0'}
@ -398,6 +482,9 @@ packages:
concat-map@0.0.1:
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
crelt@1.0.6:
resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==}
cross-spawn@7.0.6:
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
engines: {node: '>= 8'}
@ -503,6 +590,11 @@ packages:
flatted@3.3.2:
resolution: {integrity: sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==}
fsevents@2.3.3:
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
os: [darwin]
glob-parent@5.1.2:
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
engines: {node: '>= 6'}
@ -549,6 +641,9 @@ packages:
isexe@2.0.0:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
js-tokens@4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
js-yaml@4.1.0:
resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
hasBin: true
@ -576,6 +671,9 @@ packages:
lodash.merge@4.6.2:
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
magic-string@0.30.17:
resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==}
merge2@1.4.1:
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
engines: {node: '>= 8'}
@ -630,6 +728,9 @@ packages:
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
engines: {node: '>=8'}
picocolors@1.1.1:
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
picomatch@2.3.1:
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
engines: {node: '>=8.6'}
@ -662,6 +763,18 @@ packages:
resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
rollup-plugin-dts@5.3.1:
resolution: {integrity: sha512-gusMi+Z4gY/JaEQeXnB0RUdU82h1kF0WYzCWgVmV4p3hWXqelaKuCvcJawfeg+EKn2T1Ie+YWF2OiN1/L8bTVg==}
engines: {node: '>=v14.21.3'}
peerDependencies:
rollup: ^3.0
typescript: ^4.1 || ^5.0
rollup@3.29.5:
resolution: {integrity: sha512-GVsDdsbJzzy4S/v3dqWPJ7EfvZJfCHiDqe80IyrF59LYuP+e6U1LJoUqeuqRbwAWoMNoXivMNeNAOf5E22VA1w==}
engines: {node: '>=14.18.0', npm: '>=8.0.0'}
hasBin: true
run-parallel@1.2.0:
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
@ -738,13 +851,98 @@ packages:
snapshots:
'@codemirror/state@6.5.0':
'@babel/code-frame@7.26.2':
dependencies:
'@babel/helper-validator-identifier': 7.25.9
js-tokens: 4.0.0
picocolors: 1.1.1
optional: true
'@babel/helper-validator-identifier@7.25.9':
optional: true
'@codemirror/autocomplete@6.18.6':
dependencies:
'@codemirror/language': 6.10.8
'@codemirror/state': 6.5.2
'@codemirror/view': 6.36.2
'@lezer/common': 1.2.3
'@codemirror/commands@6.8.0':
dependencies:
'@codemirror/language': 6.10.8
'@codemirror/state': 6.5.2
'@codemirror/view': 6.36.2
'@lezer/common': 1.2.3
'@codemirror/lang-css@6.3.1':
dependencies:
'@codemirror/autocomplete': 6.18.6
'@codemirror/language': 6.10.8
'@codemirror/state': 6.5.2
'@lezer/common': 1.2.3
'@lezer/css': 1.1.10
'@codemirror/lang-html@6.4.9':
dependencies:
'@codemirror/autocomplete': 6.18.6
'@codemirror/lang-css': 6.3.1
'@codemirror/lang-javascript': 6.2.3
'@codemirror/language': 6.10.8
'@codemirror/state': 6.5.2
'@codemirror/view': 6.36.2
'@lezer/common': 1.2.3
'@lezer/css': 1.1.10
'@lezer/html': 1.3.10
'@codemirror/lang-javascript@6.2.3':
dependencies:
'@codemirror/autocomplete': 6.18.6
'@codemirror/language': 6.10.8
'@codemirror/lint': 6.8.4
'@codemirror/state': 6.5.2
'@codemirror/view': 6.36.2
'@lezer/common': 1.2.3
'@lezer/javascript': 1.4.21
'@codemirror/lang-markdown@6.3.2':
dependencies:
'@codemirror/autocomplete': 6.18.6
'@codemirror/lang-html': 6.4.9
'@codemirror/language': 6.10.8
'@codemirror/state': 6.5.2
'@codemirror/view': 6.36.2
'@lezer/common': 1.2.3
'@lezer/markdown': 1.4.1
'@codemirror/language@6.10.8':
dependencies:
'@codemirror/state': 6.5.2
'@codemirror/view': 6.36.2
'@lezer/common': 1.2.3
'@lezer/highlight': 1.2.1
'@lezer/lr': 1.4.2
style-mod: 4.1.2
'@codemirror/lint@6.8.4':
dependencies:
'@codemirror/state': 6.5.2
'@codemirror/view': 6.36.2
crelt: 1.0.6
'@codemirror/search@6.5.9':
dependencies:
'@codemirror/state': 6.5.2
'@codemirror/view': 6.36.2
crelt: 1.0.6
'@codemirror/state@6.5.2':
dependencies:
'@marijn/find-cluster-break': 1.0.2
'@codemirror/view@6.36.1':
'@codemirror/view@6.36.2':
dependencies:
'@codemirror/state': 6.5.0
'@codemirror/state': 6.5.2
style-mod: 4.1.2
w3c-keyname: 2.2.8
@ -877,6 +1075,51 @@ snapshots:
'@humanwhocodes/retry@0.4.1': {}
'@jridgewell/sourcemap-codec@1.5.0': {}
'@lezer/common@1.2.3': {}
'@lezer/css@1.1.10':
dependencies:
'@lezer/common': 1.2.3
'@lezer/highlight': 1.2.1
'@lezer/lr': 1.4.2
'@lezer/highlight@1.2.1':
dependencies:
'@lezer/common': 1.2.3
'@lezer/html@1.3.10':
dependencies:
'@lezer/common': 1.2.3
'@lezer/highlight': 1.2.1
'@lezer/lr': 1.4.2
'@lezer/javascript@1.4.21':
dependencies:
'@lezer/common': 1.2.3
'@lezer/highlight': 1.2.1
'@lezer/lr': 1.4.2
'@lezer/lr@1.4.2':
dependencies:
'@lezer/common': 1.2.3
'@lezer/markdown@1.4.1':
dependencies:
'@lezer/common': 1.2.3
'@lezer/highlight': 1.2.1
'@marijn/buildtool': 0.1.6
'@marijn/buildtool@0.1.6':
dependencies:
'@types/mocha': 9.1.1
acorn: 8.14.0
acorn-walk: 8.3.4
rollup: 3.29.5
rollup-plugin-dts: 5.3.1(rollup@3.29.5)(typescript@5.7.2)
typescript: 5.7.2
'@marijn/find-cluster-break@1.0.2': {}
'@nodelib/fs.scandir@2.1.5':
@ -899,6 +1142,8 @@ snapshots:
'@types/json-schema@7.0.15': {}
'@types/mocha@9.1.1': {}
'@types/node@22.10.5':
dependencies:
undici-types: 6.20.0
@ -996,6 +1241,10 @@ snapshots:
dependencies:
acorn: 8.14.0
acorn-walk@8.3.4:
dependencies:
acorn: 8.14.0
acorn@8.14.0: {}
ajv@6.12.6:
@ -1035,6 +1284,16 @@ snapshots:
ansi-styles: 4.3.0
supports-color: 7.2.0
codemirror@6.0.1:
dependencies:
'@codemirror/autocomplete': 6.18.6
'@codemirror/commands': 6.8.0
'@codemirror/language': 6.10.8
'@codemirror/lint': 6.8.4
'@codemirror/search': 6.5.9
'@codemirror/state': 6.5.2
'@codemirror/view': 6.36.2
color-convert@2.0.1:
dependencies:
color-name: 1.1.4
@ -1043,6 +1302,8 @@ snapshots:
concat-map@0.0.1: {}
crelt@1.0.6: {}
cross-spawn@7.0.6:
dependencies:
path-key: 3.1.1
@ -1191,6 +1452,9 @@ snapshots:
flatted@3.3.2: {}
fsevents@2.3.3:
optional: true
glob-parent@5.1.2:
dependencies:
is-glob: 4.0.3
@ -1224,6 +1488,9 @@ snapshots:
isexe@2.0.0: {}
js-tokens@4.0.0:
optional: true
js-yaml@4.1.0:
dependencies:
argparse: 2.0.1
@ -1249,6 +1516,10 @@ snapshots:
lodash.merge@4.6.2: {}
magic-string@0.30.17:
dependencies:
'@jridgewell/sourcemap-codec': 1.5.0
merge2@1.4.1: {}
micromatch@4.0.8:
@ -1270,10 +1541,10 @@ snapshots:
natural-compare@1.4.0: {}
obsidian@1.7.2(@codemirror/state@6.5.0)(@codemirror/view@6.36.1):
obsidian@1.7.2(@codemirror/state@6.5.2)(@codemirror/view@6.36.2):
dependencies:
'@codemirror/state': 6.5.0
'@codemirror/view': 6.36.1
'@codemirror/state': 6.5.2
'@codemirror/view': 6.36.2
'@types/codemirror': 5.60.8
moment: 2.29.4
@ -1302,6 +1573,9 @@ snapshots:
path-key@3.1.1: {}
picocolors@1.1.1:
optional: true
picomatch@2.3.1: {}
prelude-ls@1.2.1: {}
@ -1321,6 +1595,18 @@ snapshots:
reusify@1.0.4: {}
rollup-plugin-dts@5.3.1(rollup@3.29.5)(typescript@5.7.2):
dependencies:
magic-string: 0.30.17
rollup: 3.29.5
typescript: 5.7.2
optionalDependencies:
'@babel/code-frame': 7.26.2
rollup@3.29.5:
optionalDependencies:
fsevents: 2.3.3
run-parallel@1.2.0:
dependencies:
queue-microtask: 1.2.3

View file

@ -1,10 +1,14 @@
import { EventRef, Plugin, Platform } from "obsidian";
import { EventRef, Plugin, Platform, WorkspaceLeaf } from "obsidian";
import { GitHubSyncSettings, DEFAULT_SETTINGS } from "./settings/settings";
import GitHubSyncSettingsTab from "./settings/tab";
import SyncManager from "./sync-manager";
import { FileMetadata } from "./metadata-store";
import { OnboardingDialog } from "./views/onboarding/view";
import Logger from "./logger";
import {
ConflictsResolutionView,
CONFLICTS_RESOLUTION_VIEW_TYPE,
} from "./views/conflicts-resolution/view";
export default class GitHubSyncPlugin extends Plugin {
settings: GitHubSyncSettings;
@ -30,9 +34,34 @@ export default class GitHubSyncPlugin extends Plugin {
}
}
async activateView() {
const { workspace } = this.app;
let leaf: WorkspaceLeaf | null = null;
const leaves = workspace.getLeavesOfType(CONFLICTS_RESOLUTION_VIEW_TYPE);
if (leaves.length > 0) {
leaf = leaves[0];
} else {
leaf = workspace.getRightLeaf(false);
await leaf.setViewState({
type: CONFLICTS_RESOLUTION_VIEW_TYPE,
active: true,
});
}
workspace.revealLeaf(leaf);
}
async onload() {
await this.loadSettings();
this.registerView(
CONFLICTS_RESOLUTION_VIEW_TYPE,
(leaf) => new ConflictsResolutionView(leaf, this),
);
this.addRibbonIcon(
"dice",
"Activate view",
async () => await this.activateView(),
);
this.logger = new Logger(this.app.vault, this.settings.enableLogging);
this.addSettingTab(new GitHubSyncSettingsTab(this.app, this));

View file

@ -0,0 +1,142 @@
import { App } from "obsidian";
import { useEffect, useRef } from "react";
import { EditorView } from "@codemirror/view";
import { EditorState } from "@codemirror/state";
import { markdown } from "@codemirror/lang-markdown";
import { basicSetup } from "codemirror";
import diff from "./diff";
import { createDiffHighlightPlugin } from "./diff-highlight-plugin";
// Add styles for diff highlighting
const styles = document.createElement("style");
styles.innerHTML = `
.diff-remove-background {
background-color: rgba(255, 0, 0, 0.1);
}
.diff-add-background {
background-color: rgba(0, 255, 0, 0.1);
}
`;
document.head.appendChild(styles);
interface DiffViewProps {
oldText: string;
newText: string;
onResolve: (resolvedText: string) => void;
app: App;
}
const DiffView: React.FC<DiffViewProps> = ({
oldText,
newText,
onResolve,
app,
}) => {
const containerRef = useRef<HTMLDivElement>(null);
const editorViewsRef = useRef<EditorView[]>([]);
useEffect(() => {
if (!containerRef.current) return;
const createEditor = (
container: HTMLElement,
content: string,
readOnly: boolean = false,
isOriginal: boolean = false,
) => {
const differences = diff(oldText, newText);
const highlightPlugin = createDiffHighlightPlugin({
diff: differences,
isOriginal,
});
const changeListener = !readOnly
? [
EditorView.updateListener.of((update) => {
if (update.docChanged) {
onResolve(update.state.doc.toString());
}
}),
]
: [];
const state = EditorState.create({
doc: content,
extensions: [
basicSetup,
markdown(),
EditorView.lineWrapping,
EditorView.editable.of(!readOnly),
highlightPlugin,
...changeListener,
],
});
const view = new EditorView({
state,
parent: container,
});
editorViewsRef.current.push(view);
return view;
};
// Create the three editors
const originalView = createEditor(
containerRef.current.querySelector(".original-editor")!,
oldText,
true,
true,
);
const modifiedView = createEditor(
containerRef.current.querySelector(".modified-editor")!,
newText,
true,
false,
);
const resultView = createEditor(
containerRef.current.querySelector(".result-editor")!,
newText,
false,
);
return () => {
editorViewsRef.current.forEach((view) => view.destroy());
editorViewsRef.current = [];
};
}, [oldText, newText]);
return (
<div
ref={containerRef}
style={{
display: "grid",
gridTemplateColumns: "1fr 1fr",
gridTemplateRows: "1fr 1fr",
gap: "10px",
height: "100%",
}}
>
<div
className="original-editor"
style={{ border: "1px solid var(--background-modifier-border)" }}
/>
<div
className="modified-editor"
style={{ border: "1px solid var(--background-modifier-border)" }}
/>
<div
className="result-editor"
style={{
gridColumn: "1 / span 2",
border: "1px solid var(--background-modifier-border)",
}}
/>
</div>
);
};
export default DiffView;

View file

@ -0,0 +1,53 @@
import {
ViewPlugin,
Decoration,
DecorationSet,
EditorView,
} from "@codemirror/view";
import { DiffResult } from "./diff";
interface DiffHighlightPluginSpec {
diff: DiffResult[];
isOriginal: boolean;
}
export function createDiffHighlightPlugin(spec: DiffHighlightPluginSpec) {
return ViewPlugin.fromClass(
class {
decorations: DecorationSet;
constructor(view: EditorView) {
this.decorations = this.buildDecorations(view);
}
buildDecorations(view: EditorView): DecorationSet {
const doc = view.state.doc.toString();
const decorations = spec.diff
.map((d) => {
if (
(spec.isOriginal && d.type === "remove") ||
(!spec.isOriginal && d.type === "add")
) {
// Find the text position in the actual document
const pos = doc.indexOf(d.value);
if (pos !== -1) {
return Decoration.mark({
class: spec.isOriginal
? "diff-remove-background"
: "diff-add-background",
}).range(pos, pos + d.value.length);
}
}
return null;
})
.filter((d): d is NonNullable<typeof d> => d !== null);
return Decoration.set(decorations, true);
}
},
{
decorations: (v) => v.decorations,
},
);
}

View file

@ -0,0 +1,69 @@
export type DiffResult = {
type: "add" | "remove" | "equal";
value: string;
from: number;
to: number;
};
export default function diff(oldText: string, newText: string): DiffResult[] {
const oldLines = oldText.split("\n");
const newLines = newText.split("\n");
const matrix = Array(oldLines.length + 1)
.fill(null)
.map(() => Array(newLines.length + 1).fill(0));
// Fill the matrix
for (let i = 1; i <= oldLines.length; i++) {
for (let j = 1; j <= newLines.length; j++) {
if (oldLines[i - 1] === newLines[j - 1]) {
matrix[i][j] = matrix[i - 1][j - 1] + 1;
} else {
matrix[i][j] = Math.max(matrix[i - 1][j], matrix[i][j - 1]);
}
}
}
// Backtrack to find differences
const result: DiffResult[] = [];
let i = oldLines.length;
let j = newLines.length;
let position = 0;
while (i > 0 || j > 0) {
if (i > 0 && j > 0 && oldLines[i - 1] === newLines[j - 1]) {
const value = oldLines[i - 1];
result.unshift({
type: "equal",
value,
from: position,
to: position + value.length,
});
position += value.length + 1; // +1 for newline
i--;
j--;
} else if (j > 0 && (i === 0 || matrix[i][j - 1] >= matrix[i - 1][j])) {
const value = newLines[j - 1];
result.unshift({
type: "add",
value,
from: position,
to: position + value.length,
});
position += value.length + 1;
j--;
} else if (i > 0 && (j === 0 || matrix[i][j - 1] < matrix[i - 1][j])) {
const value = oldLines[i - 1];
result.unshift({
type: "remove",
value,
from: position,
to: position + value.length,
});
position += value.length + 1;
i--;
}
}
return result;
}

View file

@ -0,0 +1,75 @@
import { IconName, ItemView, WorkspaceLeaf } from "obsidian";
import { Root, createRoot } from "react-dom/client";
import DiffView from "./component";
import GitHubSyncPlugin from "src/main";
export const CONFLICTS_RESOLUTION_VIEW_TYPE = "conflicts-resolution-view";
// Test Case 1: Simple line changes
const oldText1 = `# My Document
This is a test
Some content here
Final line`;
const newText1 = `# My Document
This is a modified test
Some new content here
Final line
Added line`;
// Test Case 2: Markdown with formatting
const oldText2 = `# Title
## Subtitle
- List item 1
- List item 2
**Bold text** and *italic* text
Regular paragraph`;
const newText2 = `# Modified Title
## Subtitle
- List item 1
- List item 2
- New item
**Bold text** and *italic* text
Modified paragraph
New paragraph`;
export class ConflictsResolutionView extends ItemView {
icon: IconName = "merge";
constructor(
leaf: WorkspaceLeaf,
private plugin: GitHubSyncPlugin,
) {
super(leaf);
}
getViewType() {
return CONFLICTS_RESOLUTION_VIEW_TYPE;
}
getDisplayText() {
return "Conflicts Resolution";
}
async onOpen() {
const container = this.containerEl.children[1];
container.empty();
const root: Root = createRoot(container);
root.render(
<DiffView
oldText={oldText1}
newText={newText1}
app={this.app}
onResolve={(text) => console.log("Resolved:", text)}
// registerExtension={(ext) => this.plugin.registerEditorExtension(ext)}
/>,
);
}
async onClose() {
// Nothing to clean up.
}
}