Saya menulis add-in COM yang memperluas IDE yang sangat membutuhkannya. Ada banyak fitur yang terlibat, tetapi mari kita persempit menjadi 2 untuk kepentingan posting ini:
- Ada jendela alat Code Explorer yang menampilkan tampilan pohon yang memungkinkan pengguna menavigasi modul dan anggota mereka.
- Ada alat bantu inspeksi kode yang menampilkan tampilan datagridview yang memungkinkan pengguna menavigasi masalah kode dan secara otomatis memperbaikinya.
Kedua alat memiliki tombol "Refresh" yang memulai tugas asinkron yang mem-parsing semua kode di semua proyek yang dibuka; yang Kode Explorer menggunakan hasil parse untuk membangun treeview , dan Kode Inspeksi menggunakan hasil parse untuk menemukan masalah kode dan menampilkan hasilnya di dalam datagridview .
Yang saya coba lakukan di sini, adalah untuk berbagi hasil parse antara fitur, sehingga ketika Kode Explorer refresh, maka Kode Inspeksi tahu tentang hal itu dan bisa menyegarkan sendiri tanpa harus mengulang pekerjaan parsing bahwa Kode Explorer hanya melakukan .
Jadi apa yang saya lakukan, saya menjadikan kelas parser saya sebagai penyedia acara yang fitur-fiturnya dapat didaftarkan ke:
private void _parser_ParseCompleted(object sender, ParseCompletedEventArgs e)
{
Control.Invoke((MethodInvoker) delegate
{
Control.SolutionTree.Nodes.Clear();
foreach (var result in e.ParseResults)
{
var node = new TreeNode(result.Project.Name);
node.ImageKey = "Hourglass";
node.SelectedImageKey = node.ImageKey;
AddProjectNodes(result, node);
Control.SolutionTree.Nodes.Add(node);
}
Control.EnableRefresh();
});
}
private void _parser_ParseStarted(object sender, ParseStartedEventArgs e)
{
Control.Invoke((MethodInvoker) delegate
{
Control.EnableRefresh(false);
Control.SolutionTree.Nodes.Clear();
foreach (var name in e.ProjectNames)
{
var node = new TreeNode(name + " (parsing...)");
node.ImageKey = "Hourglass";
node.SelectedImageKey = node.ImageKey;
Control.SolutionTree.Nodes.Add(node);
}
});
}
Dan itu berhasil. Masalah yang saya alami adalah apakah ... itu berfungsi - maksud saya, ketika inspeksi kode disegarkan, parser memberi tahu penjelajah kode (dan semua orang) "Bung, penguraian seseorang, apa yang ingin Anda lakukan? " - dan ketika parsing selesai, parser memberi tahu pendengarnya "kawan, saya punya hasil parsing baru untuk Anda, apa yang ingin Anda lakukan?".
Biarkan saya membimbing Anda melalui contoh untuk menggambarkan masalah yang diciptakan ini:
- Pengguna menampilkan Kode Explorer, yang memberi tahu pengguna "tunggu, saya bekerja di sini"; pengguna terus bekerja di IDE, Code Explorer menggambar ulang sendiri, hidup itu indah.
- Pengguna kemudian memunculkan Inspeksi Kode, yang memberi tahu pengguna "tunggu, saya sedang bekerja di sini"; parser memberi tahu Code Explorer "dude, parsing seseorang, apa yang ingin Anda lakukan?" - Code Explorer memberi tahu pengguna "tunggu, saya sedang bekerja di sini"; pengguna masih dapat bekerja di IDE, tetapi tidak dapat menavigasi Code Explorer karena ini menyegarkan. Dan dia juga menunggu inspeksi kode selesai.
- Pengguna melihat masalah kode dalam hasil inspeksi yang ingin mereka atasi; mereka mengklik dua kali untuk menavigasi ke sana, mengkonfirmasi ada masalah dengan kode, dan klik tombol "Perbaiki". Modul telah dimodifikasi dan perlu diurai kembali, sehingga inspeksi kode dilanjutkan dengannya; Penjelajah Kode memberi tahu pengguna "tunggu, saya sedang bekerja di sini", ...
Lihat kemana ini? Saya tidak suka, dan saya yakin pengguna juga tidak akan menyukainya. Apa yang saya lewatkan? Bagaimana cara saya membagi hasil parse di antara fitur, tetapi tetap membiarkan pengguna mengontrol kapan fitur harus melakukan fungsinya ?
Alasan saya bertanya, adalah karena saya pikir jika saya menunda pekerjaan yang sebenarnya sampai pengguna secara aktif memutuskan untuk menyegarkan, dan "cache" hasil parse ketika mereka masuk ... baik maka saya akan menyegarkan treeview dan menemukan masalah kode pada hasil parse yang mungkin basi ... yang benar-benar membawa saya kembali ke titik awal, di mana setiap fitur bekerja dengan hasil parse sendiri: apakah ada cara saya dapat membagikan hasil parsing antara fitur dan memiliki UX yang indah?
Kode ini adalah c # , tetapi saya tidak mencari kode, saya mencari konsep .
sumber
VBAParser
dihasilkan oleh ANTLR dan memberi saya pohon parse, tetapi fitur tidak mengonsumsinya. TheRubberduckParser
take the parse tree, berjalan, dan mengeluarkan aVBProjectParseResult
yang berisiDeclaration
objek yang memiliki semuaReferences
penyelesaiannya - itulah yang dilakukan fitur untuk input .. jadi ya, ini cukup banyak situasi semua atau tidak sama sekali. TheRubberduckParser
cukup pintar untuk tidak kembali parse modul yang belum dimodifikasi sekalipun. Tetapi jika ada hambatan bukan dengan parsing, itu dengan inspeksi kode.Jawaban:
Cara saya mungkin akan mendekati ini akan menjadi kurang fokus pada memberikan hasil yang sempurna, dan sebaliknya fokus pada pendekatan upaya terbaik. Ini akan menghasilkan setidaknya perubahan berikut:
Konversikan logika yang saat ini memulai penguraian ulang untuk meminta alih-alih memulai.
Logika untuk meminta penguraian ulang mungkin berakhir dengan tampilan seperti ini:
Ini akan dipasangkan dengan logika yang membungkus parser, yang mungkin terlihat seperti ini:
Yang penting adalah bahwa pengurai berjalan sampai permintaan penguraian ulang yang paling baru telah dihormati, tetapi tidak lebih dari satu pengurai berjalan pada waktu tertentu.
Hapus
ParseStarted
panggilan balik. Meminta penguraian ulang sekarang merupakan operasi api dan lupa.Atau, konversikan untuk tidak melakukan apa pun selain menunjukkan indikator menyegarkan di beberapa bagian GUI yang tidak menghalangi interaksi pengguna.
Cobalah untuk memberikan penanganan minimal untuk hasil basi.
Dalam kasus Code Explorer, itu mungkin sesederhana mencari jumlah garis yang wajar atas dan ke bawah untuk metode yang ingin dinavigasi oleh pengguna, atau metode terdekat jika nama persis tidak ditemukan.
Saya tidak yakin apa yang cocok untuk Inspektur Kode.
Saya tidak yakin dengan detail implementasi, tetapi secara keseluruhan, ini sangat mirip dengan bagaimana editor NetBeans menangani perilaku ini. Selalu sangat cepat untuk menunjukkan bahwa saat ini menyegarkan, tetapi juga tidak memblokir akses ke fungsionalitas.
Hasil basi seringkali cukup baik - terutama bila dibandingkan dengan tanpa hasil.
sumber
ParseStarted
untuk menonaktifkan tombol [Refresh] (Control.EnableRefresh(false)
). Jika saya menghapus panggilan balik itu, dan membiarkan pengguna mengkliknya ... maka saya akan menempatkan diri saya dalam situasi di mana saya memiliki dua tugas bersamaan melakukan penguraian ... bagaimana cara menghindari ini tanpa menonaktifkan penyegaran pada semua fungsi lain saat seseorang Apakah penguraian?ParseStarted
acara, jika Anda ingin mengizinkan UI (atau komponen lainnya) terkadang memperingatkan pengguna bahwa reparasi sedang terjadi. Tentu saja, Anda mungkin ingin mendokumentasikan penelepon harus berusaha untuk tidak menghentikan pengguna dari menggunakan (akan menjadi) hasil parse saat ini basi.