дзеркало
https://github.com/l0ng-ai/openidea.git
синхронізовано 2026-11-08 19:02:17 +02:00
* Revert "Merge pull request #1805 from a-rookie-of-C-language/fix/gradle-all-tests-cwd" This reverts commit37975fd71a, reversing changes made to2028772ab2. * Revert "Merge pull request #1803 from a-rookie-of-C-language/feat/flash-taskbar-on-breakpoint" This reverts commit2028772ab2, reversing changes made to5b53b579d9. * Revert "Merge pull request #1799 from a-rookie-of-C-language/fix/mybatis-annotation-method-name" This reverts commit5b53b579d9, reversing changes made to9db90c7141. * Revert "Merge pull request #1798 from a-rookie-of-C-language/fix/squeezed-tab-close-button" This reverts commit9db90c7141, reversing changes made to3bb58ff542. * Revert "Merge pull request #1797 from a-rookie-of-C-language/fix/open-recent-path-tooltip" This reverts commit3bb58ff542, reversing changes made tof0ad100a25. * Revert "Merge pull request #1796 from a-rookie-of-C-language/fix/find-match-fg-color" This reverts commitf0ad100a25, reversing changes made tofca9d1e08f.
Цей коміт міститься в:
1 джерело
37975fd71a
коміт
b5ab3eed1f
10 files changed
+8
-138
No files matched your search
Бінарний файл не відображається.
@@ -1 +1 @@
|
||||
5e7f7adc2c49503d2278ed2a446f18f69561ce51df264100f77f50d69804c277
|
||||
c29594e55d321ee5240f8f61223d72c9095695a5b19ff1f8a25c5a6402a4a736
|
||||
@@ -70,51 +70,6 @@ fn ident(c: char) -> bool {
|
||||
c.is_alphanumeric() || c == '_' || c == '$'
|
||||
}
|
||||
|
||||
/// Index of the `(` opening a method's parameter list inside a declaration
|
||||
/// fragment. `(`s that belong to annotation arguments — `@Anno(…)` — are
|
||||
/// skipped so `@DataPermission(column = "id") int count()` finds the paren
|
||||
/// after `count`, not the one after `DataPermission`.
|
||||
fn method_paren(stmt: &str) -> Option<usize> {
|
||||
let mut rest = stmt;
|
||||
let mut base = 0;
|
||||
while let Some(i) = rest.find('(') {
|
||||
// Is the token right before this `(` an annotation name (`@Anno`, `@a.b.Anno`)?
|
||||
let before = rest[..i].trim_end();
|
||||
let annotation = before.rfind('@').is_some_and(|a| before[a + 1..].chars().all(|c| ident(c) || c == '.'));
|
||||
if !annotation {
|
||||
return Some(base + i);
|
||||
}
|
||||
// Skip the annotation's argument list (it may nest and hold literals).
|
||||
let mut depth = 1usize;
|
||||
let mut end = None;
|
||||
let mut chars = rest[i + 1..].char_indices().peekable();
|
||||
while let Some((j, c)) = chars.next() {
|
||||
match c {
|
||||
'"' | '\'' => {
|
||||
for (_, d) in chars.by_ref() {
|
||||
if d == c {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
'(' => depth += 1,
|
||||
')' => {
|
||||
depth -= 1;
|
||||
if depth == 0 {
|
||||
end = Some(i + 1 + j + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
let skip = end?;
|
||||
base += skip;
|
||||
rest = &rest[skip..];
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// The interface's name and methods (with their parameter names).
|
||||
pub fn parse_java(text: &str) -> MapperJava {
|
||||
let package =
|
||||
@@ -140,7 +95,7 @@ pub fn parse_java(text: &str) -> MapperJava {
|
||||
}
|
||||
';' if depth == 0 => {
|
||||
let stmt = &text[stmt_start..k];
|
||||
if let Some(paren) = method_paren(stmt) {
|
||||
if let Some(paren) = stmt.find('(') {
|
||||
let before = stmt[..paren].trim_end();
|
||||
let name_start = before.rfind(|c: char| !ident(c)).map_or(0, |p| p + 1);
|
||||
let method = &before[name_start..];
|
||||
@@ -406,17 +361,6 @@ mod tests {
|
||||
assert_eq!(n.line_markers(&xml)[0].tooltip, "Go to UserMapper.findById()");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn method_annotations_do_not_swallow_the_method_name() {
|
||||
// A method-level annotation with arguments: `stmt.find('(')` would land
|
||||
// inside `@DataPermission(…)` and read `DataPermission` as the name.
|
||||
let java = parse_java(
|
||||
"package com.acme;\n\npublic interface SecuredMapper {\n @DataPermission(column = \"id\", scope = (@Scope(\"self\")))\n List<User> findAll(@Param(\"org\") String org);\n\n @org.acme.Check(value = \"(nested)\")\n int count();\n}\n",
|
||||
);
|
||||
let names: Vec<_> = java.methods.iter().map(|(m, p)| (m.name.as_str(), p.clone())).collect();
|
||||
assert_eq!(names, [("findAll", vec!["org".to_owned()]), ("count", Vec::<String>::new())]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn completes_ids_and_parameters() {
|
||||
let _host = setup();
|
||||
|
||||
@@ -66,7 +66,7 @@ pub fn observe(app: &tauri::AppHandle) {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn application_active(app: &tauri::AppHandle) -> bool {
|
||||
fn application_active(app: &tauri::AppHandle) -> bool {
|
||||
// A settings window, utility window or native dialog is still this application.
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use ide_core::{EventSink, IdeEvent};
|
||||
use tauri::{AppHandle, Emitter, Manager, UserAttentionType};
|
||||
use tauri::{AppHandle, Emitter};
|
||||
|
||||
/// Name of the single backend → UI event. Payload: [`IdeEvent`].
|
||||
pub const IDE_EVENT: &str = "ide://event";
|
||||
@@ -38,31 +38,8 @@ pub struct TauriSink {
|
||||
pub window: Option<String>,
|
||||
}
|
||||
|
||||
/// A debug session stopped on a breakpoint: bounce/flash the taskbar icon
|
||||
/// (IDEA) unless the user is already looking at an OpenIDEA window. The focus
|
||||
/// check and the request both touch the windowing system, so they run on the
|
||||
/// main thread; `emit` itself can come from any debug worker thread.
|
||||
fn flash_taskbar_unless_focused(app: &AppHandle) {
|
||||
let handle = app.clone();
|
||||
let _ = app.run_on_main_thread(move || {
|
||||
if crate::application_focus::application_active(&handle) {
|
||||
return;
|
||||
}
|
||||
for window in handle.webview_windows().values() {
|
||||
let _ = window.request_user_attention(Some(UserAttentionType::Informational));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
impl EventSink for TauriSink {
|
||||
fn emit(&self, event: IdeEvent) {
|
||||
if matches!(
|
||||
&event,
|
||||
IdeEvent::Debug { event: ide_core::event::DebugEvent::Stopped { reason, .. }, .. }
|
||||
if matches!(reason.as_str(), "breakpoint" | "function breakpoint")
|
||||
) {
|
||||
flash_taskbar_unless_focused(&self.app);
|
||||
}
|
||||
let result = match &self.window {
|
||||
Some(label) => {
|
||||
for target in crate::windows::document_windows(&self.app, label) {
|
||||
|
||||
@@ -18,7 +18,6 @@ export const findLocals = {
|
||||
export const findStyles = {
|
||||
".cm-openidea-findMatch": {
|
||||
backgroundColor: "var(--editor-search)",
|
||||
color: "var(--fg-search-match, inherit)",
|
||||
borderRadius: "2px",
|
||||
},
|
||||
".cm-openidea-findExcluded": {
|
||||
@@ -30,7 +29,6 @@ export const findStyles = {
|
||||
},
|
||||
".cm-openidea-findMatch-current": {
|
||||
backgroundColor: "var(--editor-search-current)",
|
||||
color: "var(--fg-search-match, inherit)",
|
||||
outline: "1px solid color-mix(in srgb, var(--editor-search-current) 60%, var(--fg-strong))",
|
||||
},
|
||||
};
|
||||
|
||||
@@ -813,15 +813,6 @@ describe("project producers", () => {
|
||||
expect(
|
||||
produceDirectory({ path: `${ROOT}/src/test/java/com/acme`, root: ROOT, configs: gradle })!.config!.args,
|
||||
).toEqual(["test", "--tests", "com.acme.*"]);
|
||||
// A module's tests run from the build root so `./gradlew` resolves,
|
||||
// qualified by the module's Gradle path.
|
||||
const dir = produceDirectory({ path: `${ROOT}/services/api/src/test/java`, root: ROOT, configs: gradle })!;
|
||||
expect(dir.config).toMatchObject({ cwd: null });
|
||||
expect(dir.config!.args).toEqual([":services:api:test"]);
|
||||
expect(
|
||||
produceDirectory({ path: `${ROOT}/services/api/src/test/java/com/acme`, root: ROOT, configs: gradle })!.config!
|
||||
.args,
|
||||
).toEqual([":services:api:test", "--tests", "com.acme.*"]);
|
||||
expect(produceDirectory({ path: `${ROOT}/src/main`, root: ROOT, configs })).toBeNull();
|
||||
expect(produceDirectory({ path: ROOT, root: ROOT, configs })).toBeNull();
|
||||
});
|
||||
|
||||
@@ -14,7 +14,6 @@ import { ipcPath, isSameOrInside } from "@/platform/paths";
|
||||
import { isTestPath } from "@/platform/languageSettings";
|
||||
import { currentRoots } from "@/platform/projectRoots";
|
||||
import { applicationConfig, jvmModuleDir } from "./application";
|
||||
import { useBuildModel } from "@/platform/buildModel";
|
||||
import { formatArgs } from "./configs";
|
||||
import { goGenerateConfig } from "./goGenerate";
|
||||
import { goTestParts } from "./goArguments";
|
||||
@@ -1147,27 +1146,6 @@ function rubyDirectory(
|
||||
return make(minitest, label, [...args, relToCwd(minitest)]);
|
||||
}
|
||||
|
||||
/**
|
||||
* The Gradle build and project path a module directory belongs to, so a module
|
||||
* test run can stay in the build root (where `./gradlew` resolves) and qualify
|
||||
* its task (`:services:api:test`). `null` for non-Gradle bases and modules the
|
||||
* base configuration already runs. Without a loaded model, the Gradle path is
|
||||
* guessed from the directory's segments — right for the standard layout the
|
||||
* wrapper itself implies.
|
||||
*/
|
||||
function gradleOwnerFor(module: string, base: RunConfig): { dir: string | null; path: string } | null {
|
||||
if (base.kind !== "gradle" || !module || module === base.cwd) return null;
|
||||
const dir = module.replace(/\\/g, "/");
|
||||
const gradle = useBuildModel
|
||||
.getState()
|
||||
.model?.gradle?.find((g) => g.projects.some((p) => p.dir.replace(/\\/g, "/") === dir));
|
||||
const project = gradle?.projects.find((p) => p.dir.replace(/\\/g, "/") === dir);
|
||||
return {
|
||||
dir: gradle?.dir ?? base.cwd,
|
||||
path: project?.path ?? `:${module.split("/").join(":")}`,
|
||||
};
|
||||
}
|
||||
|
||||
export function produceDirectory(input: ContextInput): Produced | null {
|
||||
input = scopedInput(input);
|
||||
const { root } = input;
|
||||
@@ -1203,20 +1181,11 @@ export function produceDirectory(input: ContextInput): Produced | null {
|
||||
const base = closest(["gradle", "maven"]);
|
||||
if (base) {
|
||||
const module = jvmModuleDir(rel + "/x.java", input.configs);
|
||||
// Gradle in a multi-module project: run from the build root so the
|
||||
// wrapper (`./gradlew`) resolves, qualifying the task with the module's
|
||||
// Gradle path (`services/api` → `:services:api:test`). Other builds run
|
||||
// in the module directory as before.
|
||||
const owner = gradleOwnerFor(module, base);
|
||||
const moduleBase = { ...base, cwd: owner ? owner.dir : module || base.cwd };
|
||||
const moduleArgs = (base: RunConfig): string[] => {
|
||||
if (!owner) return [...base.args];
|
||||
return base.args.map((a) => (a === "test" ? `${owner.path}:test` : a));
|
||||
};
|
||||
if (!jvmPackage) return make(moduleBase, "All Tests", moduleArgs(base));
|
||||
const moduleBase = { ...base, cwd: module || base.cwd };
|
||||
if (!jvmPackage) return make(moduleBase, "All Tests", [...base.args]);
|
||||
const pkg = jvmPackage[2]!.replace(/\//g, ".");
|
||||
return base.kind === "gradle"
|
||||
? make(moduleBase, `Tests in '${pkg}'`, [...moduleArgs(base), "--tests", `${pkg}.*`])
|
||||
? make(moduleBase, `Tests in '${pkg}'`, [...base.args, "--tests", `${pkg}.*`])
|
||||
: make(moduleBase, `Tests in '${pkg}'`, [
|
||||
...base.args,
|
||||
`-Dtest=${pkg}.**.*`,
|
||||
|
||||
@@ -273,9 +273,7 @@ export function MenuList({ items, onDone, onCloseLevel, autoFocusFirst = true, .
|
||||
<span className={styles.icon} data-menu-icon={!r.checked && r.icon ? "" : undefined}>
|
||||
{r.checked ? <Icon name="check" size={13} /> : r.icon ? <Icon name={r.icon} size={14} /> : null}
|
||||
</span>
|
||||
<span className={styles.label} title={r.label}>
|
||||
{r.label}
|
||||
</span>
|
||||
<span className={styles.label}>{r.label}</span>
|
||||
{r.shortcut && <span className={styles.shortcut}>{r.shortcut}</span>}
|
||||
{hasSub && <Icon name="chevron-right" size={14} className={styles.subArrow} />}
|
||||
</button>
|
||||
|
||||
@@ -140,13 +140,6 @@
|
||||
flex: 0 1 auto;
|
||||
min-width: 40px;
|
||||
}
|
||||
/* A closable tab keeps room for its close slot: only the label shrinks. */
|
||||
.squeeze .closable {
|
||||
min-width: 64px;
|
||||
}
|
||||
.squeeze .closeSlot {
|
||||
flex: none;
|
||||
}
|
||||
.squeeze .tabButton {
|
||||
flex: 1 1 auto;
|
||||
min-width: 0;
|
||||
|
||||
Reference in new issue
Заблокувати користувача