mirror of
https://github.com/l0ng-ai/openidea.git
synced 2026-11-06 00:07:50 +00:00
feat(php): list PHP versions newest first
The interpreter list kept discovery order (PATH, Homebrew, phpbrew, phpenv, Herd…) and the language levels ran from 5.6 up to 8.5, so finding a version meant reading every row. Detected interpreters are now sorted newest first, number by number (8.3.12 before 8.3.9; stable, so the PATH install stays first among equal versions), and the language level select and status bar menu list Auto, then 8.5 down to 5.6. Saved levels are unaffected. With Default selected, the Version row showed the first list entry, which after sorting is not necessarily the php Default runs; it now shows the version of the php found on PATH.
This commit is contained in:
@@ -143,7 +143,7 @@ fn nvm_bins(dir: &Path) -> Vec<PathBuf> {
|
||||
}
|
||||
|
||||
/// `v22.10.1` as `[22, 10, 1]`: v22 is newer than v9, v20.10 newer than v20.9.
|
||||
fn version_key(name: &str) -> Vec<u64> {
|
||||
pub fn version_key(name: &str) -> Vec<u64> {
|
||||
name.trim_start_matches('v').split('.').map(|n| n.parse().unwrap_or(0)).collect()
|
||||
}
|
||||
|
||||
|
||||
@@ -367,7 +367,7 @@ fn php() -> Vec<Sdk> {
|
||||
}
|
||||
}
|
||||
let found = dedupe_by_real_path(found);
|
||||
par_map(&found, |(path, source)| {
|
||||
let mut sdks = par_map(&found, |(path, source)| {
|
||||
let version = query(path, &["-r", "echo PHP_VERSION;"], VERSION_TIMEOUT)?;
|
||||
let version = version.trim().to_owned();
|
||||
if version.is_empty() {
|
||||
@@ -381,7 +381,16 @@ fn php() -> Vec<Sdk> {
|
||||
home: path.parent().and_then(Path::parent).map(Into::into),
|
||||
extra: None,
|
||||
})
|
||||
})
|
||||
});
|
||||
newest_first(&mut sdks);
|
||||
sdks
|
||||
}
|
||||
|
||||
/// Newest version first, number by number (8.3.12 before 8.3.9); stable, so on equal
|
||||
/// versions the `PATH` install stays first.
|
||||
pub(crate) fn newest_first(sdks: &mut [Sdk]) {
|
||||
let key = |s: &Sdk| ide_core::tool_path::version_key(s.version.as_deref().unwrap_or(""));
|
||||
sdks.sort_by_key(|s| std::cmp::Reverse(key(s)));
|
||||
}
|
||||
|
||||
fn node() -> Vec<Sdk> {
|
||||
|
||||
@@ -1322,7 +1322,29 @@ fn php_sources_and_selected_interpreter() {
|
||||
assert_eq!(source("/opt/homebrew/opt/php@8.2/bin/php"), "homebrew");
|
||||
assert_eq!(source("/home/me/bin/php"), "path");
|
||||
|
||||
use crate::discover::{is_versioned_php_name, versioned_php_in};
|
||||
use crate::discover::{is_versioned_php_name, newest_first, versioned_php_in};
|
||||
let sdk = |path: &str, version: &str| crate::Sdk {
|
||||
path: std::path::PathBuf::from(path).into(),
|
||||
name: format!("PHP {version}"),
|
||||
version: Some(version.into()),
|
||||
source: "path".into(),
|
||||
home: None,
|
||||
extra: None,
|
||||
};
|
||||
let mut sdks = vec![
|
||||
sdk("/opt/homebrew/bin/php", "8.4.1"),
|
||||
sdk("/opt/homebrew/opt/php@8.1/bin/php", "8.1.31"),
|
||||
sdk("/opt/homebrew/opt/php@8.2/bin/php", "8.2.20"),
|
||||
sdk("/home/me/.phpbrew/php/php-8.3.9/bin/php", "8.3.9"),
|
||||
sdk("/home/me/.phpbrew/php/php-8.3.12/bin/php", "8.3.12"),
|
||||
sdk("/home/me/.phpbrew/php/php-7.4.33/bin/php", "7.4.33"),
|
||||
sdk("/usr/bin/php", "8.4.1"),
|
||||
];
|
||||
newest_first(&mut sdks);
|
||||
let order: Vec<_> = sdks.iter().map(|s| s.version.clone().unwrap()).collect();
|
||||
assert_eq!(order, ["8.4.1", "8.4.1", "8.3.12", "8.3.9", "8.2.20", "8.1.31", "7.4.33"]);
|
||||
// Stable: on equal versions the PATH install stays first.
|
||||
assert_eq!(sdks[0].path.0, std::path::PathBuf::from("/opt/homebrew/bin/php"));
|
||||
for name in ["php8.1", "php81", "php8", "php8.3.exe"] {
|
||||
assert!(is_versioned_php_name(name), "{name}");
|
||||
}
|
||||
|
||||
@@ -78,7 +78,9 @@ describe("languages settings", () => {
|
||||
}
|
||||
expect(PHP_LANGUAGE_LEVELS[0]).toBe("");
|
||||
expect(PHP_LANGUAGE_LEVELS).toContain("5.6");
|
||||
expect(PHP_LANGUAGE_LEVELS.at(-1)).toBe("8.5");
|
||||
// Newest first after Auto (#1557).
|
||||
expect(PHP_LANGUAGE_LEVELS[1]).toBe("8.5");
|
||||
expect(PHP_LANGUAGE_LEVELS.at(-1)).toBe("5.6");
|
||||
});
|
||||
|
||||
it("finds the PHP page by its language level", () => {
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
* Build Tools › Maven: the toolchain each language's server and run configurations
|
||||
* use (applied by `ide-sdk` when language servers start and when run configurations load).
|
||||
*/
|
||||
import { useId, useMemo } from "react";
|
||||
import { useEffect, useId, useMemo, useState } from "react";
|
||||
import { call, commands } from "@/platform/ipc";
|
||||
import { IconButton, Input, type SelectOption } from "@/ui";
|
||||
import { PHP_LANGUAGE_LEVELS } from "@/platform/languageSettings";
|
||||
import { GlobListEditor, Row, Section, Select, Toggle } from "../components/Form";
|
||||
@@ -117,13 +118,31 @@ const PHP_LEVEL_OPTIONS: SelectOption[] = PHP_LANGUAGE_LEVELS.map((level) =>
|
||||
level ? { value: level, label: level } : { value: "", label: "Auto", detail: "from composer.json" },
|
||||
);
|
||||
|
||||
/** The `php` on `PATH` (what the Default interpreter runs), looked up while `enabled`. */
|
||||
function usePathPhp(enabled: boolean): string | null {
|
||||
const [path, setPath] = useState<string | null>(null);
|
||||
useEffect(() => {
|
||||
if (!enabled) return;
|
||||
let live = true;
|
||||
call(commands.sdkLocateTools(["php"], null))
|
||||
.then((r) => live && setPath(r.tools[0]?.path ?? null))
|
||||
.catch(() => {});
|
||||
return () => {
|
||||
live = false;
|
||||
};
|
||||
}, [enabled]);
|
||||
return path;
|
||||
}
|
||||
|
||||
export function PhpPage() {
|
||||
const [interpreter] = useSetting<string>("languages.php.interpreter");
|
||||
const [level, setLevel] = useSetting<string>("languages.php.languageLevel");
|
||||
const [includePaths, setIncludePaths] = useSetting<string[]>("languages.php.includePaths");
|
||||
const [stubs, setStubs] = useSetting<string[]>("languages.php.stubs");
|
||||
const { list } = useDetected("php");
|
||||
const selected = list.find((s) => s.path === interpreter) ?? (interpreter ? undefined : list[0]);
|
||||
const pathPhp = usePathPhp(!interpreter);
|
||||
// Default runs the `php` on PATH: the list is newest first, so it isn't necessarily `list[0]`.
|
||||
const selected = list.find((s) => s.path === (interpreter || pathPhp));
|
||||
return (
|
||||
<div className={styles.page}>
|
||||
<Section>
|
||||
|
||||
@@ -62,21 +62,21 @@ const DEFAULT_RUFF_FORMATTER: ExternalFormatterValid = {
|
||||
languages: ["python"],
|
||||
};
|
||||
|
||||
/** `languages.php.languageLevel` values; `""` = Auto (from `composer.json`). */
|
||||
/** `languages.php.languageLevel` values, newest first; `""` = Auto (from `composer.json`). */
|
||||
export const PHP_LANGUAGE_LEVELS = [
|
||||
"",
|
||||
"5.6",
|
||||
"7.0",
|
||||
"7.1",
|
||||
"7.2",
|
||||
"7.3",
|
||||
"7.4",
|
||||
"8.0",
|
||||
"8.1",
|
||||
"8.2",
|
||||
"8.3",
|
||||
"8.4",
|
||||
"8.5",
|
||||
"8.4",
|
||||
"8.3",
|
||||
"8.2",
|
||||
"8.1",
|
||||
"8.0",
|
||||
"7.4",
|
||||
"7.3",
|
||||
"7.2",
|
||||
"7.1",
|
||||
"7.0",
|
||||
"5.6",
|
||||
] as const;
|
||||
|
||||
export interface LanguagesValid {
|
||||
|
||||
Reference in New Issue
Block a user