mirror of
https://github.com/storytold/cadcraft.git
synced 2026-10-28 21:06:56 -06:00
* Report DWGPREFIX, DWGTITLED, FILEDIA, CMDECHO and more from GETVAR (#1715) * Keep CMDECHO and FILEDIA in session settings so they survive drawing switches (#1715) * Leave LOGINNAME out of GETVAR so scripts and agents can't read the user's login name Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Brandon Thomas <echelon@gmail.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
Brandon Thomas
parent
f119610287
commit
f8f13c3f4e
@@ -400,6 +400,10 @@ pub struct Settings {
|
||||
pub pickfirst: bool,
|
||||
/// ACADLSPASDOC: acad.lsp loads into every drawing, not once per session.
|
||||
pub acadlspasdoc: bool,
|
||||
/// CMDECHO: kept for routines that switch command echo around their commands; no command reads it yet.
|
||||
pub cmdecho: bool,
|
||||
/// FILEDIA: kept for routines that switch file dialogs off around a script; no command reads it yet.
|
||||
pub filedia: bool,
|
||||
pub pickadd: bool,
|
||||
/// PICKDRAG: false = two-click windows (0), true = clicks or dragging (2).
|
||||
/// Drag-only mode (1) is not supported yet.
|
||||
@@ -491,6 +495,8 @@ impl Default for Settings {
|
||||
aperture: 10.0,
|
||||
pickfirst: true,
|
||||
acadlspasdoc: false,
|
||||
cmdecho: true,
|
||||
filedia: true,
|
||||
pickadd: true,
|
||||
pickdrag: true,
|
||||
pickstyle: 1,
|
||||
|
||||
@@ -437,6 +437,24 @@ fn tables_and_variables() {
|
||||
assert_eq!(ok(&mut s, "(getvar \"NOSUCHVAR\")"), "nil");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn getvar_drawing_and_session_variables() {
|
||||
let mut s = session();
|
||||
assert_eq!(ok(&mut s, "(list (getvar \"DWGPREFIX\") (getvar \"DWGTITLED\"))"), "(\"\" 0)");
|
||||
assert_eq!(ok(&mut s, "(list (getvar \"FILEDIA\") (getvar \"CMDECHO\") (getvar \"TILEMODE\"))"), "(1 1 1)");
|
||||
assert_eq!(ok(&mut s, "(setvar \"FILEDIA\" 0) (setvar \"CMDECHO\" 0) (getvar \"FILEDIA\")"), "0");
|
||||
// Both belong to the session, so they survive a switch to another drawing.
|
||||
s.new_drawing(true);
|
||||
assert_eq!(ok(&mut s, "(list (getvar \"FILEDIA\") (getvar \"CMDECHO\"))"), "(0 0)");
|
||||
assert_eq!(ok(&mut s, "(getvar \"CMDACTIVE\")"), "0");
|
||||
let dir = std::env::temp_dir();
|
||||
let file = dir.join("lisp_getvar_test.dxf");
|
||||
s.state_mut().unwrap().path = Some(file.to_string_lossy().into_owned());
|
||||
let want = format!("{}{}", dir.to_string_lossy().trim_end_matches(std::path::MAIN_SEPARATOR), std::path::MAIN_SEPARATOR);
|
||||
assert_eq!(crate::sysvars::get(&s, "DWGPREFIX"), Some(serde_json::json!(want)));
|
||||
assert_eq!(ok(&mut s, "(getvar \"DWGTITLED\")"), "1");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn input_functions_take_supplied_answers() {
|
||||
let mut s = session();
|
||||
|
||||
@@ -55,6 +55,8 @@ const SESSION_VARS: &[&str] = &[
|
||||
"APERTURE",
|
||||
"PICKFIRST",
|
||||
"ACADLSPASDOC",
|
||||
"CMDECHO",
|
||||
"FILEDIA",
|
||||
"PICKADD",
|
||||
"PICKDRAG",
|
||||
"PICKSTYLE",
|
||||
@@ -129,6 +131,8 @@ pub fn get(s: &Session, name: &str) -> Option<Value> {
|
||||
"APERTURE" => json!(st.aperture),
|
||||
"PICKFIRST" => json!(i32::from(st.pickfirst)),
|
||||
"ACADLSPASDOC" => json!(i32::from(st.acadlspasdoc)),
|
||||
"CMDECHO" => json!(i32::from(st.cmdecho)),
|
||||
"FILEDIA" => json!(i32::from(st.filedia)),
|
||||
"PICKADD" => json!(i32::from(st.pickadd)),
|
||||
"PICKDRAG" => json!(i32::from(st.pickdrag) * 2),
|
||||
"PICKSTYLE" => json!(st.pickstyle),
|
||||
@@ -149,6 +153,12 @@ pub fn get(s: &Session, name: &str) -> Option<Value> {
|
||||
"CMDNAMES" => json!(s.running.as_ref().map(|r| r.id.to_ascii_uppercase()).unwrap_or_default()),
|
||||
"DWGNAME" => json!(s.state().map(|d| d.title.clone()).unwrap_or_default()),
|
||||
"DBMOD" => json!(s.state().map(|d| i32::from(d.is_dirty())).unwrap_or(0)),
|
||||
// The drawing's folder with a trailing separator ("" while it has no file); DWGTITLED is 1 once it has one.
|
||||
"DWGPREFIX" => json!(s.state().ok().and_then(|d| d.path.as_deref()).map(dwg_prefix).unwrap_or_default()),
|
||||
"DWGTITLED" => json!(s.state().map(|d| i32::from(d.path.is_some())).unwrap_or(0)),
|
||||
"CMDACTIVE" => json!(i32::from(s.running.is_some())),
|
||||
"TILEMODE" => json!(i32::from(s.state().is_ok_and(|d| d.space.layout().is_none()))),
|
||||
"PLATFORM" => json!(std::env::consts::OS),
|
||||
"BLOCKEDITOR" => json!(i32::from(s.state().is_ok_and(|d| d.block_edit.is_some()))),
|
||||
// The template NEW/QNEW start from (a profile setting, like FONTALT; "" = none).
|
||||
"QNEWTEMPLATE" => json!(crate::cmd::file::qnew_template()),
|
||||
@@ -186,6 +196,21 @@ pub fn get(s: &Session, name: &str) -> Option<Value> {
|
||||
Some(v)
|
||||
}
|
||||
|
||||
/// DWGPREFIX: the folder of the drawing file, made absolute, with a trailing separator.
|
||||
fn dwg_prefix(path: &str) -> String {
|
||||
let full = std::path::absolute(path).unwrap_or_else(|_| std::path::PathBuf::from(path));
|
||||
match full.parent() {
|
||||
Some(dir) => {
|
||||
let mut text = dir.to_string_lossy().into_owned();
|
||||
if !text.ends_with(std::path::MAIN_SEPARATOR) {
|
||||
text.push(std::path::MAIN_SEPARATOR);
|
||||
}
|
||||
text
|
||||
}
|
||||
None => String::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn as_bool(v: &Value) -> Option<bool> {
|
||||
v.as_bool().or_else(|| v.as_i64().map(|i| i != 0)).or_else(|| v.as_str().and_then(|s| s.trim().parse::<i64>().ok()).map(|i| i != 0))
|
||||
}
|
||||
@@ -205,8 +230,25 @@ fn as_pt(v: &Value) -> Option<cadcraft_geom::Vec2> {
|
||||
}
|
||||
|
||||
/// Variables `get` reports from session or drawing state that `set` can't change.
|
||||
const READ_ONLY: &[&str] =
|
||||
&["CMDNAMES", "DWGNAME", "DBMOD", "BLOCKEDITOR", "CTAB", "LASTPOINT", "VIEWCTR", "VIEWSIZE", "EXTMIN", "EXTMAX", "UNDOCTL", "UNDOMARKS"];
|
||||
const READ_ONLY: &[&str] = &[
|
||||
"CMDNAMES",
|
||||
"DWGNAME",
|
||||
"DWGPREFIX",
|
||||
"DWGTITLED",
|
||||
"CMDACTIVE",
|
||||
"TILEMODE",
|
||||
"PLATFORM",
|
||||
"DBMOD",
|
||||
"BLOCKEDITOR",
|
||||
"CTAB",
|
||||
"LASTPOINT",
|
||||
"VIEWCTR",
|
||||
"VIEWSIZE",
|
||||
"EXTMIN",
|
||||
"EXTMAX",
|
||||
"UNDOCTL",
|
||||
"UNDOMARKS",
|
||||
];
|
||||
|
||||
pub fn is_read_only(name: &str) -> bool {
|
||||
READ_ONLY.iter().any(|r| r.eq_ignore_ascii_case(name.trim())) || table::is_read_only(&name.trim().to_ascii_uppercase())
|
||||
@@ -302,6 +344,8 @@ pub fn set(s: &mut Session, name: &str, v: &Value) -> Result<()> {
|
||||
"APERTURE" => st.aperture = as_f64(v).ok_or_else(bad)?.clamp(1.0, 50.0),
|
||||
"PICKFIRST" => st.pickfirst = as_bool(v).ok_or_else(bad)?,
|
||||
"ACADLSPASDOC" => st.acadlspasdoc = as_bool(v).ok_or_else(bad)?,
|
||||
"CMDECHO" => st.cmdecho = small(v, 1).ok_or_else(bad)? == 1,
|
||||
"FILEDIA" => st.filedia = small(v, 1).ok_or_else(bad)? == 1,
|
||||
"PICKADD" => st.pickadd = as_bool(v).ok_or_else(bad)?,
|
||||
"PICKDRAG" => st.pickdrag = as_i(v).filter(|b| matches!(b, 0 | 2)).map(|b| b == 2).ok_or_else(bad)?,
|
||||
"PICKSTYLE" => st.pickstyle = as_i(v).filter(|b| (0..=3).contains(b)).and_then(|b| u8::try_from(b).ok()).ok_or_else(bad)?,
|
||||
|
||||
Reference in New Issue
Block a user