Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

didChange with full text can't work #16

Closed
saierXP opened this issue Nov 26, 2023 · 1 comment
Closed

didChange with full text can't work #16

saierXP opened this issue Nov 26, 2023 · 1 comment
Labels
bug Something isn't working

Comments

@saierXP
Copy link

saierXP commented Nov 26, 2023

执行全部文本变动的通知,插入新值这里似乎发生了死锁,服务器后续不工作也没有报错,客户端也无法正常连接了。

rime-ls/src/lsp.rs

Lines 60 to 63 in 0b8ad0c

async fn on_change(&self, params: TextDocumentItem) {
let rope = Rope::from_str(&params.text);
self.documents.insert(params.uri.to_string(), rope);
}

通过把这里的 获取文本rope的操作,放到下面进行文本局部插入的if分支里,就可以进行全部文本替换和局部插入。

rime-ls/src/lsp.rs

Lines 333 to 336 in 0b8ad0c

let mut rope = self
.documents
.get_mut(params.text_document.uri.as_str())
.unwrap();

不懂Rust,不知道上面修改后的原理,我去看dashMap的文档和issue里提到过insert会有死锁的问题。

JavaScript lsp客户端测试代码 需要nodejs和 vscode-jsonrpc 库依赖 根据实际修改初始化的initializationOptions值 切换下面didChange部分range更改和全文更改的注释,观察服务器返回的补全,文本打开默认值是zh
const net = require('net');
const {
	createMessageConnection,
	SocketMessageReader,
	SocketMessageWriter
} = require("vscode-jsonrpc");

const sleep = (delay) => new Promise((resolve) => setTimeout(resolve, delay))

function main() {
	const argv = process.argv;
	const client = new net.Socket();

	client.connect(9257, '127.0.0.1', () => {
		console.log('Connected to LSP server');
	});

	const reader = new SocketMessageReader(client);
	const writer = new SocketMessageWriter(client);
	const connection = createMessageConnection(reader, writer);

	connection.onNotification('window/logMessage', (params) => {
		console.log('Received message:', params);
	});

	connection.onNotification('window/workDoneProgress/create', (params) => {
		console.log('Received :', params);
	});

	connection.onRequest('workspace/executeCommand', (params) => {
		console.log('Received command:', params);
	});

	connection.listen();

	client.on('close', () => {
		console.log('Connection closed');
	});

	connection.onNotification((method, params) => {
		console.log(`Notification: ${method} ${JSON.stringify(params, null, 2)}`);
	});

	connection.sendRequest("initialize", {
			"initializationOptions": {
				"shared_data_dir": "D:\\App\\Rime\\weasel-0.15.0\\data",
				"user_data_dir": "D:\\Temp\\Rime\\lsp",
				"log_dir": "D:\\Temp\\Rime\\lsp\\log",
				"max_candidates": 10,
				"trigger_characters": [],
				"schema_trigger_character": "&"
			},
			"capabilities": {
				"textDocument": {
					"synchronization": {
						"dynamicRegistration": true
					}
				},
				"window": {
					"showMessage": {
						"messageActionItem": {
							"additionalPropertiesSupport": false
						}
					}
				}
			}
		})
		.then(async (e) => {
			console.log("Resp: ", JSON.stringify(e, null, 2))
			await connection.sendNotification("initialized", {})
			await connection.sendNotification("textDocument/didOpen", {
				"textDocument": {
					"languageId": "text",
					"text": "zh",
					"uri": "file:///res://Temp/Rime/test.txt",
					"version": 1,
				}
			});
			await sleep(300);

			connection.sendNotification("textDocument/didChange", {
				"textDocument": {
					"uri": "file:///res://Temp/Rime/test.txt",
					"version": 100
				},
				"contentChanges": [{
					"text": "qi",
					"range": {
						"start": {
							"line": 0,
							"character": 0
						},
						"end": {
							"line": 0,
							"character": 0
						}
					}
				}],
				"rangeLength": 0
			});

                       // connection.sendNotification("textDocument/didChange",{"textDocument":{"uri":"file:///res://Temp/Rime/test.txt","version":100}, "contentChanges":[{"text":"kou"}]});
			await sleep(600);

			var c = await connection.sendRequest("textDocument/completion", {
				"textDocument": {
					"uri": "file:///res://Temp/Rime/test.txt",
				},
				"position": {
					"line": 0,
					"character": 2,
				},
			});

			console.log("Comp:", JSON.stringify(c, null, 2));
		});

}
main();
@wlh320
Copy link
Owner

wlh320 commented Nov 26, 2023

感谢,确实可以稳定复现死锁问题,原因我认为跟 dashmap 的文档说的一样,就是在插入时当前线程还有一个对该 map 内的 value 的引用。

把获取 dashmap 内容的引用的代码放进第一个 if 分支会比较合理,避免了进入第二个分支时在外面的不必要的引用。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants