mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-06-12 08:54:57 +03:00
Auto-build: copilot (python) from 7fa279c
This commit is contained in:
@@ -0,0 +1,514 @@
|
||||
# subsystem-info v1.0 — Compact summary of 1C subsystem structure
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
param(
|
||||
[Parameter(Mandatory=$true)][Alias('Path')][string]$SubsystemPath,
|
||||
[ValidateSet("overview","content","ci","tree","full")]
|
||||
[string]$Mode = "overview",
|
||||
[string]$Name,
|
||||
[int]$Limit = 150,
|
||||
[int]$Offset = 0,
|
||||
[string]$OutFile
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
|
||||
|
||||
# --- Output helper ---
|
||||
$script:lines = @()
|
||||
function Out([string]$text) { $script:lines += $text }
|
||||
|
||||
# --- Resolve path ---
|
||||
if (-not [System.IO.Path]::IsPathRooted($SubsystemPath)) {
|
||||
$SubsystemPath = Join-Path (Get-Location).Path $SubsystemPath
|
||||
}
|
||||
|
||||
# --- Helper: get LocalString text ---
|
||||
function Get-MLText($node) {
|
||||
if (-not $node -or -not $node.HasChildNodes) { return "" }
|
||||
foreach ($item in $node.ChildNodes) {
|
||||
if ($item.NodeType -ne 'Element') { continue }
|
||||
$lang = ""; $content = ""
|
||||
foreach ($c in $item.ChildNodes) {
|
||||
if ($c.NodeType -ne 'Element') { continue }
|
||||
if ($c.LocalName -eq "lang") { $lang = $c.InnerText }
|
||||
if ($c.LocalName -eq "content") { $content = $c.InnerText }
|
||||
}
|
||||
if ($lang -eq "ru" -and $content) { return $content }
|
||||
}
|
||||
# fallback: first item
|
||||
foreach ($item in $node.ChildNodes) {
|
||||
if ($item.NodeType -ne 'Element') { continue }
|
||||
foreach ($c in $item.ChildNodes) {
|
||||
if ($c.NodeType -ne 'Element') { continue }
|
||||
if ($c.LocalName -eq "content" -and $c.InnerText) { return $c.InnerText }
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
# --- Helper: load subsystem XML ---
|
||||
function Load-SubsystemXml([string]$xmlPath) {
|
||||
[xml]$doc = Get-Content -Path $xmlPath -Encoding UTF8
|
||||
$ns = New-Object System.Xml.XmlNamespaceManager($doc.NameTable)
|
||||
$ns.AddNamespace("md", "http://v8.1c.ru/8.3/MDClasses")
|
||||
$ns.AddNamespace("v8", "http://v8.1c.ru/8.1/data/core")
|
||||
$ns.AddNamespace("xr", "http://v8.1c.ru/8.3/xcf/readable")
|
||||
$ns.AddNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance")
|
||||
$sub = $doc.SelectSingleNode("/md:MetaDataObject/md:Subsystem", $ns)
|
||||
if (-not $sub) {
|
||||
Write-Host "[ERROR] Not a valid subsystem XML: $xmlPath"
|
||||
exit 1
|
||||
}
|
||||
return @{ Doc=$doc; Ns=$ns; Sub=$sub }
|
||||
}
|
||||
|
||||
# --- Helper: get content items ---
|
||||
function Get-ContentItems($props, $ns) {
|
||||
$items = @()
|
||||
$contentNode = $props.SelectSingleNode("md:Content", $ns)
|
||||
if (-not $contentNode -or -not $contentNode.HasChildNodes) { return $items }
|
||||
foreach ($item in $contentNode.SelectNodes("xr:Item", $ns)) {
|
||||
$items += $item.InnerText
|
||||
}
|
||||
return $items
|
||||
}
|
||||
|
||||
# --- Helper: get child subsystem names ---
|
||||
function Get-ChildNames($sub, $ns) {
|
||||
$names = @()
|
||||
$co = $sub.SelectSingleNode("md:ChildObjects", $ns)
|
||||
if (-not $co -or -not $co.HasChildNodes) { return $names }
|
||||
foreach ($child in $co.ChildNodes) {
|
||||
if ($child.NodeType -eq 'Element' -and $child.LocalName -eq "Subsystem") {
|
||||
$names += $child.InnerText
|
||||
}
|
||||
}
|
||||
return $names
|
||||
}
|
||||
|
||||
# --- Helper: group content by type ---
|
||||
function Group-ContentByType($items) {
|
||||
$groups = [ordered]@{}
|
||||
foreach ($item in $items) {
|
||||
if ($item -match '^([^.]+)\.(.+)$') {
|
||||
$type = $Matches[1]
|
||||
$name = $Matches[2]
|
||||
} elseif ($item -match '^[0-9a-fA-F]{8}-') {
|
||||
$type = "[UUID]"
|
||||
$name = $item
|
||||
} else {
|
||||
$type = "[Other]"
|
||||
$name = $item
|
||||
}
|
||||
if (-not $groups.Contains($type)) { $groups[$type] = @() }
|
||||
$groups[$type] += $name
|
||||
}
|
||||
return $groups
|
||||
}
|
||||
|
||||
# --- Helper: find subsystem dir from XML path ---
|
||||
function Get-SubsystemDir([string]$xmlPath) {
|
||||
$dir = [System.IO.Path]::GetDirectoryName($xmlPath)
|
||||
$baseName = [System.IO.Path]::GetFileNameWithoutExtension($xmlPath)
|
||||
return Join-Path $dir $baseName
|
||||
}
|
||||
|
||||
# --- Show functions for full mode ---
|
||||
function Show-Overview {
|
||||
Out "Подсистема: $subName"
|
||||
if ($synonym -and $synonym -ne $subName) { Out "Синоним: $synonym" }
|
||||
if ($commentText) { Out "Комментарий: $commentText" }
|
||||
Out "ВключатьВКомандныйИнтерфейс: $inclCI"
|
||||
Out "ИспользоватьОднуКоманду: $useOneCmd"
|
||||
if ($explanation) { Out "Пояснение: $explanation" }
|
||||
if ($picText) { Out "Картинка: $picText" }
|
||||
if ($contentItems.Count -gt 0) {
|
||||
$parts = @()
|
||||
foreach ($type in $groups.Keys) {
|
||||
$parts += "$type`: $($groups[$type].Count)"
|
||||
}
|
||||
Out "Состав: $($contentItems.Count) объектов ($($parts -join ', '))"
|
||||
} else {
|
||||
Out "Состав: пусто"
|
||||
}
|
||||
if ($childNames.Count -gt 0) {
|
||||
Out "Дочерние подсистемы ($($childNames.Count)): $($childNames -join ', ')"
|
||||
}
|
||||
if ($hasCI) {
|
||||
Out "Командный интерфейс: есть"
|
||||
}
|
||||
}
|
||||
|
||||
function Show-Content {
|
||||
Out "Состав подсистемы $subName ($($contentItems.Count) объектов):"
|
||||
Out ""
|
||||
if ($Name) {
|
||||
if ($groups.Contains($Name)) {
|
||||
$filtered = $groups[$Name]
|
||||
Out "$Name ($($filtered.Count)):"
|
||||
foreach ($n in $filtered) { Out " $n" }
|
||||
} else {
|
||||
Out "[INFO] Тип '$Name' не найден в составе."
|
||||
Out "Доступные типы: $($groups.Keys -join ', ')"
|
||||
}
|
||||
} else {
|
||||
foreach ($type in $groups.Keys) {
|
||||
Out "$type ($($groups[$type].Count)):"
|
||||
foreach ($n in $groups[$type]) { Out " $n" }
|
||||
Out ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function Show-CI {
|
||||
$localSubDir = Get-SubsystemDir $SubsystemPath
|
||||
$localCiPath = Join-Path (Join-Path $localSubDir "Ext") "CommandInterface.xml"
|
||||
|
||||
if (-not (Test-Path $localCiPath)) {
|
||||
Out "Командный интерфейс: $subName"
|
||||
Out ""
|
||||
Out "Файл CommandInterface.xml не найден."
|
||||
Out "Путь: $localCiPath"
|
||||
} else {
|
||||
[xml]$ciDoc = Get-Content -Path $localCiPath -Encoding UTF8
|
||||
$ciNs = New-Object System.Xml.XmlNamespaceManager($ciDoc.NameTable)
|
||||
$ciNs.AddNamespace("ci", "http://v8.1c.ru/8.3/xcf/extrnprops")
|
||||
$ciNs.AddNamespace("xr", "http://v8.1c.ru/8.3/xcf/readable")
|
||||
|
||||
$ciRoot = $ciDoc.DocumentElement
|
||||
|
||||
Out "Командный интерфейс: $subName"
|
||||
Out ""
|
||||
|
||||
# --- CommandsVisibility ---
|
||||
$visSection = $ciRoot.SelectSingleNode("ci:CommandsVisibility", $ciNs)
|
||||
if ($visSection) {
|
||||
$hidden = @(); $shown = @()
|
||||
foreach ($cmd in $visSection.SelectNodes("ci:Command", $ciNs)) {
|
||||
$cmdName = $cmd.GetAttribute("name")
|
||||
$vis = $cmd.SelectSingleNode("ci:Visibility/xr:Common", $ciNs)
|
||||
if ($vis -and $vis.InnerText -eq "false") { $hidden += $cmdName }
|
||||
else { $shown += $cmdName }
|
||||
}
|
||||
$total = $hidden.Count + $shown.Count
|
||||
if (-not $Name -or $Name -eq "visibility") {
|
||||
Out "Видимость ($total):"
|
||||
if ($hidden.Count -gt 0) {
|
||||
Out " СКРЫТО ($($hidden.Count)):"
|
||||
foreach ($h in $hidden) { Out " $h" }
|
||||
}
|
||||
if ($shown.Count -gt 0) {
|
||||
Out " ПОКАЗАНО ($($shown.Count)):"
|
||||
foreach ($s in $shown) { Out " $s" }
|
||||
}
|
||||
Out ""
|
||||
}
|
||||
}
|
||||
|
||||
# --- CommandsPlacement ---
|
||||
$placeSection = $ciRoot.SelectSingleNode("ci:CommandsPlacement", $ciNs)
|
||||
if ($placeSection) {
|
||||
$placements = @()
|
||||
foreach ($cmd in $placeSection.SelectNodes("ci:Command", $ciNs)) {
|
||||
$cmdName = $cmd.GetAttribute("name")
|
||||
$grp = $cmd.SelectSingleNode("ci:CommandGroup", $ciNs)
|
||||
$pl = $cmd.SelectSingleNode("ci:Placement", $ciNs)
|
||||
$grpText = if ($grp) { $grp.InnerText } else { "?" }
|
||||
$plText = if ($pl) { $pl.InnerText } else { "?" }
|
||||
$placements += @{ Name=$cmdName; Group=$grpText; Placement=$plText }
|
||||
}
|
||||
if ((-not $Name -or $Name -eq "placement") -and $placements.Count -gt 0) {
|
||||
Out "Размещение ($($placements.Count)):"
|
||||
$arrow = [char]0x2192
|
||||
foreach ($p in $placements) {
|
||||
Out " $($p.Name) $arrow $($p.Group) ($($p.Placement))"
|
||||
}
|
||||
Out ""
|
||||
}
|
||||
}
|
||||
|
||||
# --- CommandsOrder ---
|
||||
$orderSection = $ciRoot.SelectSingleNode("ci:CommandsOrder", $ciNs)
|
||||
if ($orderSection) {
|
||||
$orderGroups = [ordered]@{}
|
||||
foreach ($cmd in $orderSection.SelectNodes("ci:Command", $ciNs)) {
|
||||
$cmdName = $cmd.GetAttribute("name")
|
||||
$grp = $cmd.SelectSingleNode("ci:CommandGroup", $ciNs)
|
||||
$grpText = if ($grp) { $grp.InnerText } else { "?" }
|
||||
if (-not $orderGroups.Contains($grpText)) { $orderGroups[$grpText] = @() }
|
||||
$orderGroups[$grpText] += $cmdName
|
||||
}
|
||||
$totalOrder = 0
|
||||
foreach ($k in $orderGroups.Keys) { $totalOrder += $orderGroups[$k].Count }
|
||||
if ((-not $Name -or $Name -eq "order") -and $totalOrder -gt 0) {
|
||||
Out "Порядок команд ($totalOrder):"
|
||||
foreach ($grpName in $orderGroups.Keys) {
|
||||
Out " [$grpName]:"
|
||||
foreach ($c in $orderGroups[$grpName]) { Out " $c" }
|
||||
}
|
||||
Out ""
|
||||
}
|
||||
}
|
||||
|
||||
# --- SubsystemsOrder ---
|
||||
$subOrderSection = $ciRoot.SelectSingleNode("ci:SubsystemsOrder", $ciNs)
|
||||
if ($subOrderSection) {
|
||||
$subOrder = @()
|
||||
foreach ($s in $subOrderSection.SelectNodes("ci:Subsystem", $ciNs)) {
|
||||
$subOrder += $s.InnerText
|
||||
}
|
||||
if ((-not $Name -or $Name -eq "subsystems") -and $subOrder.Count -gt 0) {
|
||||
Out "Порядок подсистем ($($subOrder.Count)):"
|
||||
for ($i = 0; $i -lt $subOrder.Count; $i++) {
|
||||
Out " $($i+1). $($subOrder[$i])"
|
||||
}
|
||||
Out ""
|
||||
}
|
||||
}
|
||||
|
||||
# --- GroupsOrder ---
|
||||
$grpOrderSection = $ciRoot.SelectSingleNode("ci:GroupsOrder", $ciNs)
|
||||
if ($grpOrderSection) {
|
||||
$grpOrder = @()
|
||||
foreach ($g in $grpOrderSection.SelectNodes("ci:Group", $ciNs)) {
|
||||
$grpOrder += $g.InnerText
|
||||
}
|
||||
if ((-not $Name -or $Name -eq "groups") -and $grpOrder.Count -gt 0) {
|
||||
Out "Порядок групп ($($grpOrder.Count)):"
|
||||
foreach ($g in $grpOrder) { Out " $g" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# ============================================================
|
||||
# Mode: tree
|
||||
# ============================================================
|
||||
if ($Mode -eq "tree") {
|
||||
$isDir = Test-Path $SubsystemPath -PathType Container
|
||||
$rootDir = $null
|
||||
$rootXml = $null
|
||||
|
||||
if ($isDir) {
|
||||
# Subsystems/ directory — show all top-level subsystems
|
||||
$rootDir = $SubsystemPath
|
||||
} else {
|
||||
# Specific subsystem XML — show tree from this subsystem
|
||||
if (-not (Test-Path $SubsystemPath)) {
|
||||
Write-Host "[ERROR] File not found: $SubsystemPath"
|
||||
exit 1
|
||||
}
|
||||
$rootXml = $SubsystemPath
|
||||
}
|
||||
|
||||
# Box-drawing chars (PS 5.1 compatible)
|
||||
$script:T_BRANCH = [char]0x251C + [char]0x2500 + [char]0x2500 + " " # ├──
|
||||
$script:T_LAST = [char]0x2514 + [char]0x2500 + [char]0x2500 + " " # └──
|
||||
$script:T_PIPE = [char]0x2502 + " " # │
|
||||
$script:T_ARROW = [char]0x2192 # →
|
||||
|
||||
function Get-TreeLine([string]$xmlPath) {
|
||||
$parsed = Load-SubsystemXml $xmlPath
|
||||
$sub = $parsed.Sub; $ns = $parsed.Ns
|
||||
$props = $sub.SelectSingleNode("md:Properties", $ns)
|
||||
$name = $props.SelectSingleNode("md:Name", $ns).InnerText
|
||||
|
||||
$markers = @()
|
||||
$subDir = Get-SubsystemDir $xmlPath
|
||||
$ciPath = Join-Path (Join-Path $subDir "Ext") "CommandInterface.xml"
|
||||
if (Test-Path $ciPath) { $markers += "CI" }
|
||||
$useOne = $props.SelectSingleNode("md:UseOneCommand", $ns)
|
||||
if ($useOne -and $useOne.InnerText -eq "true") { $markers += "OneCmd" }
|
||||
$inclCI = $props.SelectSingleNode("md:IncludeInCommandInterface", $ns)
|
||||
if ($inclCI -and $inclCI.InnerText -eq "false") { $markers += "Скрыт" }
|
||||
$markerStr = if ($markers.Count -gt 0) { " [$($markers -join ', ')]" } else { "" }
|
||||
|
||||
$contentItems = @(Get-ContentItems $props $ns)
|
||||
$childNames = @(Get-ChildNames $sub $ns)
|
||||
$childStr = if ($childNames.Count -gt 0) { ", $($childNames.Count) дочерних" } else { "" }
|
||||
|
||||
return @{
|
||||
Label = "$name$markerStr ($($contentItems.Count) объектов$childStr)"
|
||||
SubDir = $subDir
|
||||
ChildNames = $childNames
|
||||
}
|
||||
}
|
||||
|
||||
function Build-TreeEntry([string]$xmlPath, [string]$prefix, [bool]$isLast, [bool]$isRoot) {
|
||||
$info = Get-TreeLine $xmlPath
|
||||
|
||||
$connector = if ($isRoot) { "" } elseif ($isLast) { $script:T_LAST } else { $script:T_BRANCH }
|
||||
Out "$prefix$connector$($info.Label)"
|
||||
|
||||
if ($info.ChildNames.Count -gt 0) {
|
||||
$childPrefix = if ($isRoot) { "" } elseif ($isLast) { "$prefix " } else { "$prefix$($script:T_PIPE)" }
|
||||
$subsDir = Join-Path $info.SubDir "Subsystems"
|
||||
for ($i = 0; $i -lt $info.ChildNames.Count; $i++) {
|
||||
$childXml = Join-Path $subsDir "$($info.ChildNames[$i]).xml"
|
||||
$childIsLast = ($i -eq $info.ChildNames.Count - 1)
|
||||
if (Test-Path $childXml) {
|
||||
Build-TreeEntry $childXml $childPrefix $childIsLast $false
|
||||
} else {
|
||||
$conn2 = if ($childIsLast) { $script:T_LAST } else { $script:T_BRANCH }
|
||||
Out "$childPrefix$conn2$($info.ChildNames[$i]) [NOT FOUND]"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($rootDir) {
|
||||
$label = Split-Path $rootDir -Leaf
|
||||
Out "Дерево подсистем от: $label/"
|
||||
Out ""
|
||||
$xmlFiles = @(Get-ChildItem $rootDir -Filter "*.xml" -File | Sort-Object Name)
|
||||
if ($Name) {
|
||||
$xmlFiles = @($xmlFiles | Where-Object { $_.BaseName -eq $Name })
|
||||
if ($xmlFiles.Count -eq 0) {
|
||||
Write-Host "[ERROR] Subsystem '$Name' not found in $rootDir"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
for ($i = 0; $i -lt $xmlFiles.Count; $i++) {
|
||||
Build-TreeEntry $xmlFiles[$i].FullName "" ($i -eq $xmlFiles.Count - 1) $true
|
||||
}
|
||||
} else {
|
||||
Build-TreeEntry $rootXml "" $true $true
|
||||
}
|
||||
|
||||
} elseif ($Mode -eq "ci") {
|
||||
# ============================================================
|
||||
# Mode: ci — CommandInterface.xml
|
||||
# ============================================================
|
||||
if (Test-Path $SubsystemPath -PathType Container) {
|
||||
Write-Host "[ERROR] ci mode requires a subsystem .xml file, not a directory"
|
||||
exit 1
|
||||
}
|
||||
# File not found — check Dir/Name/Name.xml → Dir/Name.xml
|
||||
if (-not (Test-Path $SubsystemPath)) {
|
||||
$fn = [System.IO.Path]::GetFileNameWithoutExtension($SubsystemPath)
|
||||
$pd = Split-Path $SubsystemPath
|
||||
if ($fn -eq (Split-Path $pd -Leaf)) {
|
||||
$c = Join-Path (Split-Path $pd) "$fn.xml"
|
||||
if (Test-Path $c) { $SubsystemPath = $c }
|
||||
}
|
||||
}
|
||||
if (-not (Test-Path $SubsystemPath)) {
|
||||
Write-Host "[ERROR] File not found: $SubsystemPath"
|
||||
exit 1
|
||||
}
|
||||
|
||||
$parsed = Load-SubsystemXml $SubsystemPath
|
||||
$sub = $parsed.Sub; $ns = $parsed.Ns
|
||||
$props = $sub.SelectSingleNode("md:Properties", $ns)
|
||||
$subName = $props.SelectSingleNode("md:Name", $ns).InnerText
|
||||
|
||||
Show-CI
|
||||
|
||||
} else {
|
||||
# ============================================================
|
||||
# Mode: overview / content — requires a subsystem XML file
|
||||
# ============================================================
|
||||
if (Test-Path $SubsystemPath -PathType Container) {
|
||||
$dirName = Split-Path $SubsystemPath -Leaf
|
||||
$candidate = Join-Path $SubsystemPath "$dirName.xml"
|
||||
$sibling = Join-Path (Split-Path $SubsystemPath) "$dirName.xml"
|
||||
if (Test-Path $candidate) {
|
||||
$SubsystemPath = $candidate
|
||||
} elseif (Test-Path $sibling) {
|
||||
$SubsystemPath = $sibling
|
||||
} else {
|
||||
Write-Host "[ERROR] No $dirName.xml found in directory. Use -Mode tree for directory listing."
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
# File not found — check Dir/Name/Name.xml → Dir/Name.xml
|
||||
if (-not (Test-Path $SubsystemPath)) {
|
||||
$fn = [System.IO.Path]::GetFileNameWithoutExtension($SubsystemPath)
|
||||
$pd = Split-Path $SubsystemPath
|
||||
if ($fn -eq (Split-Path $pd -Leaf)) {
|
||||
$c = Join-Path (Split-Path $pd) "$fn.xml"
|
||||
if (Test-Path $c) { $SubsystemPath = $c }
|
||||
}
|
||||
}
|
||||
if (-not (Test-Path $SubsystemPath)) {
|
||||
Write-Host "[ERROR] File not found: $SubsystemPath"
|
||||
exit 1
|
||||
}
|
||||
|
||||
$parsed = Load-SubsystemXml $SubsystemPath
|
||||
$sub = $parsed.Sub; $ns = $parsed.Ns
|
||||
$props = $sub.SelectSingleNode("md:Properties", $ns)
|
||||
|
||||
$subName = $props.SelectSingleNode("md:Name", $ns).InnerText
|
||||
$synonym = Get-MLText $props.SelectSingleNode("md:Synonym", $ns)
|
||||
$comment = $props.SelectSingleNode("md:Comment", $ns)
|
||||
$commentText = if ($comment -and $comment.InnerText) { $comment.InnerText } else { "" }
|
||||
$inclHelp = $props.SelectSingleNode("md:IncludeHelpInContents", $ns).InnerText
|
||||
$inclCI = $props.SelectSingleNode("md:IncludeInCommandInterface", $ns).InnerText
|
||||
$useOneCmd = $props.SelectSingleNode("md:UseOneCommand", $ns).InnerText
|
||||
$explanation = Get-MLText $props.SelectSingleNode("md:Explanation", $ns)
|
||||
|
||||
# Picture
|
||||
$picNode = $props.SelectSingleNode("md:Picture", $ns)
|
||||
$picText = ""
|
||||
if ($picNode -and $picNode.HasChildNodes) {
|
||||
$picRef = $picNode.SelectSingleNode("xr:Ref", $ns)
|
||||
if ($picRef -and $picRef.InnerText) { $picText = $picRef.InnerText }
|
||||
}
|
||||
|
||||
# Content
|
||||
$contentItems = @(Get-ContentItems $props $ns)
|
||||
$groups = Group-ContentByType $contentItems
|
||||
|
||||
# Children
|
||||
$childNames = @(Get-ChildNames $sub $ns)
|
||||
|
||||
# CI presence
|
||||
$subDir = Get-SubsystemDir $SubsystemPath
|
||||
$ciPath = Join-Path (Join-Path $subDir "Ext") "CommandInterface.xml"
|
||||
$hasCI = Test-Path $ciPath
|
||||
|
||||
if ($Mode -eq "overview") {
|
||||
Show-Overview
|
||||
} elseif ($Mode -eq "content") {
|
||||
Show-Content
|
||||
} elseif ($Mode -eq "full") {
|
||||
Show-Overview
|
||||
Out ""; Out "--- content ---"; Out ""
|
||||
Show-Content
|
||||
Out ""; Out "--- ci ---"; Out ""
|
||||
Show-CI
|
||||
}
|
||||
}
|
||||
|
||||
# --- Pagination and output ---
|
||||
$totalLines = $script:lines.Count
|
||||
$outLines = $script:lines
|
||||
|
||||
if ($Offset -gt 0) {
|
||||
if ($Offset -ge $totalLines) {
|
||||
Write-Host "[INFO] Offset $Offset exceeds total lines ($totalLines). Nothing to show."
|
||||
exit 0
|
||||
}
|
||||
$outLines = $outLines[$Offset..($totalLines - 1)]
|
||||
}
|
||||
|
||||
if ($Limit -gt 0 -and $outLines.Count -gt $Limit) {
|
||||
$shown = $outLines[0..($Limit - 1)]
|
||||
$remaining = $totalLines - $Offset - $Limit
|
||||
$shown += ""
|
||||
$shown += "[ОБРЕЗАНО] Показано $Limit из $totalLines строк. Используйте -Offset $($Offset + $Limit) для продолжения."
|
||||
$outLines = $shown
|
||||
}
|
||||
|
||||
if ($OutFile) {
|
||||
if (-not [System.IO.Path]::IsPathRooted($OutFile)) {
|
||||
$OutFile = Join-Path (Get-Location).Path $OutFile
|
||||
}
|
||||
$utf8 = New-Object System.Text.UTF8Encoding($true)
|
||||
[System.IO.File]::WriteAllLines($OutFile, $outLines, $utf8)
|
||||
Write-Host "Output written to $OutFile"
|
||||
} else {
|
||||
foreach ($l in $outLines) { Write-Host $l }
|
||||
}
|
||||
@@ -0,0 +1,525 @@
|
||||
#!/usr/bin/env python3
|
||||
# subsystem-info v1.0 — Compact summary of 1C subsystem structure
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from collections import OrderedDict
|
||||
from lxml import etree
|
||||
|
||||
sys.stdout.reconfigure(encoding="utf-8")
|
||||
sys.stderr.reconfigure(encoding="utf-8")
|
||||
|
||||
# --- Argument parsing ---
|
||||
parser = argparse.ArgumentParser(description="Analyze 1C subsystem structure", allow_abbrev=False)
|
||||
parser.add_argument("-SubsystemPath", "-Path", required=True, help="Path to subsystem XML or Subsystems/ directory")
|
||||
parser.add_argument("-Mode", choices=["overview", "content", "ci", "tree", "full"], default="overview", help="Output mode")
|
||||
parser.add_argument("-Name", default="", help="Filter by name/type")
|
||||
parser.add_argument("-Limit", type=int, default=150, help="Max lines to show")
|
||||
parser.add_argument("-Offset", type=int, default=0, help="Lines to skip")
|
||||
parser.add_argument("-OutFile", default="", help="Write output to file")
|
||||
args = parser.parse_args()
|
||||
|
||||
# --- Output helper ---
|
||||
lines_buf = []
|
||||
|
||||
def out(text=""):
|
||||
lines_buf.append(text)
|
||||
|
||||
# --- Resolve path ---
|
||||
subsystem_path = args.SubsystemPath
|
||||
if not os.path.isabs(subsystem_path):
|
||||
subsystem_path = os.path.join(os.getcwd(), subsystem_path)
|
||||
|
||||
NS = {
|
||||
"md": "http://v8.1c.ru/8.3/MDClasses",
|
||||
"v8": "http://v8.1c.ru/8.1/data/core",
|
||||
"xr": "http://v8.1c.ru/8.3/xcf/readable",
|
||||
"xsi": "http://www.w3.org/2001/XMLSchema-instance",
|
||||
}
|
||||
|
||||
CI_NS = {
|
||||
"ci": "http://v8.1c.ru/8.3/xcf/extrnprops",
|
||||
"xr": "http://v8.1c.ru/8.3/xcf/readable",
|
||||
}
|
||||
|
||||
# --- Helper: get LocalString text ---
|
||||
def get_ml_text(node):
|
||||
if node is None:
|
||||
return ""
|
||||
# Look for v8:item children
|
||||
for item in node:
|
||||
if not isinstance(item.tag, str):
|
||||
continue
|
||||
lang = ""
|
||||
content = ""
|
||||
for c in item:
|
||||
if not isinstance(c.tag, str):
|
||||
continue
|
||||
local = etree.QName(c.tag).localname
|
||||
if local == "lang":
|
||||
lang = c.text or ""
|
||||
if local == "content":
|
||||
content = c.text or ""
|
||||
if lang == "ru" and content:
|
||||
return content
|
||||
# fallback: first item
|
||||
for item in node:
|
||||
if not isinstance(item.tag, str):
|
||||
continue
|
||||
for c in item:
|
||||
if not isinstance(c.tag, str):
|
||||
continue
|
||||
local = etree.QName(c.tag).localname
|
||||
if local == "content" and c.text:
|
||||
return c.text
|
||||
return ""
|
||||
|
||||
# --- Helper: load subsystem XML ---
|
||||
def load_subsystem_xml(xml_path):
|
||||
tree = etree.parse(xml_path, etree.XMLParser(remove_blank_text=False))
|
||||
doc_root = tree.getroot()
|
||||
sub = doc_root.find("md:Subsystem", NS)
|
||||
if sub is None:
|
||||
print(f"[ERROR] Not a valid subsystem XML: {xml_path}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
return {"Doc": doc_root, "Sub": sub}
|
||||
|
||||
# --- Helper: get content items ---
|
||||
def get_content_items(props):
|
||||
items = []
|
||||
content_node = props.find("md:Content", NS)
|
||||
if content_node is None:
|
||||
return items
|
||||
for item in content_node.findall("xr:Item", NS):
|
||||
if item.text:
|
||||
items.append(item.text)
|
||||
return items
|
||||
|
||||
# --- Helper: get child subsystem names ---
|
||||
def get_child_names(sub):
|
||||
names = []
|
||||
co = sub.find("md:ChildObjects", NS)
|
||||
if co is None:
|
||||
return names
|
||||
for child in co:
|
||||
if not isinstance(child.tag, str):
|
||||
continue
|
||||
if etree.QName(child.tag).localname == "Subsystem":
|
||||
names.append(child.text or "")
|
||||
return names
|
||||
|
||||
# --- Helper: group content by type ---
|
||||
def group_content_by_type(items):
|
||||
groups = OrderedDict()
|
||||
for item in items:
|
||||
m = re.match(r'^([^.]+)\.(.+)$', item)
|
||||
if m:
|
||||
type_name = m.group(1)
|
||||
name = m.group(2)
|
||||
elif re.match(r'^[0-9a-fA-F]{8}-', item):
|
||||
type_name = "[UUID]"
|
||||
name = item
|
||||
else:
|
||||
type_name = "[Other]"
|
||||
name = item
|
||||
if type_name not in groups:
|
||||
groups[type_name] = []
|
||||
groups[type_name].append(name)
|
||||
return groups
|
||||
|
||||
# --- Helper: find subsystem dir from XML path ---
|
||||
def get_subsystem_dir(xml_path):
|
||||
dir_name = os.path.dirname(xml_path)
|
||||
base_name = os.path.splitext(os.path.basename(xml_path))[0]
|
||||
return os.path.join(dir_name, base_name)
|
||||
|
||||
# --- Show functions ---
|
||||
def show_overview(sub_name, synonym, comment_text, incl_ci, use_one_cmd,
|
||||
explanation, pic_text, content_items, groups, child_names, has_ci):
|
||||
out(f"Подсистема: {sub_name}")
|
||||
if synonym and synonym != sub_name:
|
||||
out(f"Синоним: {synonym}")
|
||||
if comment_text:
|
||||
out(f"Комментарий: {comment_text}")
|
||||
out(f"ВключатьВКомандныйИнтерфейс: {incl_ci}")
|
||||
out(f"ИспользоватьОднуКоманду: {use_one_cmd}")
|
||||
if explanation:
|
||||
out(f"Пояснение: {explanation}")
|
||||
if pic_text:
|
||||
out(f"Картинка: {pic_text}")
|
||||
if len(content_items) > 0:
|
||||
parts = []
|
||||
for type_name in groups:
|
||||
parts.append(f"{type_name}: {len(groups[type_name])}")
|
||||
out(f"Состав: {len(content_items)} объектов ({', '.join(parts)})")
|
||||
else:
|
||||
out("Состав: пусто")
|
||||
if len(child_names) > 0:
|
||||
out(f"Дочерние подсистемы ({len(child_names)}): {', '.join(child_names)}")
|
||||
if has_ci:
|
||||
out("Командный интерфейс: есть")
|
||||
|
||||
|
||||
def show_content(sub_name, content_items, groups, name_filter):
|
||||
out(f"Состав подсистемы {sub_name} ({len(content_items)} объектов):")
|
||||
out()
|
||||
if name_filter:
|
||||
if name_filter in groups:
|
||||
filtered = groups[name_filter]
|
||||
out(f"{name_filter} ({len(filtered)}):")
|
||||
for n in filtered:
|
||||
out(f" {n}")
|
||||
else:
|
||||
out(f"[INFO] Тип '{name_filter}' не найден в составе.")
|
||||
out(f"Доступные типы: {', '.join(groups.keys())}")
|
||||
else:
|
||||
for type_name in groups:
|
||||
out(f"{type_name} ({len(groups[type_name])}):")
|
||||
for n in groups[type_name]:
|
||||
out(f" {n}")
|
||||
out()
|
||||
|
||||
|
||||
def show_ci(sub_name, subsystem_path_local):
|
||||
local_sub_dir = get_subsystem_dir(subsystem_path_local)
|
||||
local_ci_path = os.path.join(local_sub_dir, "Ext", "CommandInterface.xml")
|
||||
|
||||
if not os.path.isfile(local_ci_path):
|
||||
out(f"Командный интерфейс: {sub_name}")
|
||||
out()
|
||||
out("Файл CommandInterface.xml не найден.")
|
||||
out(f"Путь: {local_ci_path}")
|
||||
else:
|
||||
ci_tree = etree.parse(local_ci_path, etree.XMLParser(remove_blank_text=False))
|
||||
ci_root = ci_tree.getroot()
|
||||
|
||||
out(f"Командный интерфейс: {sub_name}")
|
||||
out()
|
||||
|
||||
# --- CommandsVisibility ---
|
||||
vis_section = ci_root.find("ci:CommandsVisibility", CI_NS)
|
||||
if vis_section is not None:
|
||||
hidden = []
|
||||
shown = []
|
||||
for cmd in vis_section.findall("ci:Command", CI_NS):
|
||||
cmd_name = cmd.get("name", "")
|
||||
vis = cmd.find("ci:Visibility/xr:Common", CI_NS)
|
||||
if vis is not None and vis.text == "false":
|
||||
hidden.append(cmd_name)
|
||||
else:
|
||||
shown.append(cmd_name)
|
||||
total = len(hidden) + len(shown)
|
||||
if not args.Name or args.Name == "visibility":
|
||||
out(f"Видимость ({total}):")
|
||||
if hidden:
|
||||
out(f" СКРЫТО ({len(hidden)}):")
|
||||
for h in hidden:
|
||||
out(f" {h}")
|
||||
if shown:
|
||||
out(f" ПОКАЗАНО ({len(shown)}):")
|
||||
for s in shown:
|
||||
out(f" {s}")
|
||||
out()
|
||||
|
||||
# --- CommandsPlacement ---
|
||||
place_section = ci_root.find("ci:CommandsPlacement", CI_NS)
|
||||
if place_section is not None:
|
||||
placements = []
|
||||
for cmd in place_section.findall("ci:Command", CI_NS):
|
||||
cmd_name = cmd.get("name", "")
|
||||
grp = cmd.find("ci:CommandGroup", CI_NS)
|
||||
pl = cmd.find("ci:Placement", CI_NS)
|
||||
grp_text = grp.text if grp is not None and grp.text else "?"
|
||||
pl_text = pl.text if pl is not None and pl.text else "?"
|
||||
placements.append({"Name": cmd_name, "Group": grp_text, "Placement": pl_text})
|
||||
if (not args.Name or args.Name == "placement") and placements:
|
||||
arrow = "\u2192"
|
||||
out(f"Размещение ({len(placements)}):")
|
||||
for p in placements:
|
||||
out(f" {p['Name']} {arrow} {p['Group']} ({p['Placement']})")
|
||||
out()
|
||||
|
||||
# --- CommandsOrder ---
|
||||
order_section = ci_root.find("ci:CommandsOrder", CI_NS)
|
||||
if order_section is not None:
|
||||
order_groups = OrderedDict()
|
||||
for cmd in order_section.findall("ci:Command", CI_NS):
|
||||
cmd_name = cmd.get("name", "")
|
||||
grp = cmd.find("ci:CommandGroup", CI_NS)
|
||||
grp_text = grp.text if grp is not None and grp.text else "?"
|
||||
if grp_text not in order_groups:
|
||||
order_groups[grp_text] = []
|
||||
order_groups[grp_text].append(cmd_name)
|
||||
total_order = sum(len(v) for v in order_groups.values())
|
||||
if (not args.Name or args.Name == "order") and total_order > 0:
|
||||
out(f"Порядок команд ({total_order}):")
|
||||
for grp_name, cmds in order_groups.items():
|
||||
out(f" [{grp_name}]:")
|
||||
for c in cmds:
|
||||
out(f" {c}")
|
||||
out()
|
||||
|
||||
# --- SubsystemsOrder ---
|
||||
sub_order_section = ci_root.find("ci:SubsystemsOrder", CI_NS)
|
||||
if sub_order_section is not None:
|
||||
sub_order = []
|
||||
for s in sub_order_section.findall("ci:Subsystem", CI_NS):
|
||||
if s.text:
|
||||
sub_order.append(s.text)
|
||||
if (not args.Name or args.Name == "subsystems") and sub_order:
|
||||
out(f"Порядок подсистем ({len(sub_order)}):")
|
||||
for i, s in enumerate(sub_order):
|
||||
out(f" {i + 1}. {s}")
|
||||
out()
|
||||
|
||||
# --- GroupsOrder ---
|
||||
grp_order_section = ci_root.find("ci:GroupsOrder", CI_NS)
|
||||
if grp_order_section is not None:
|
||||
grp_order = []
|
||||
for g in grp_order_section.findall("ci:Group", CI_NS):
|
||||
if g.text:
|
||||
grp_order.append(g.text)
|
||||
if (not args.Name or args.Name == "groups") and grp_order:
|
||||
out(f"Порядок групп ({len(grp_order)}):")
|
||||
for g in grp_order:
|
||||
out(f" {g}")
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Mode: tree
|
||||
# ============================================================
|
||||
if args.Mode == "tree":
|
||||
is_dir = os.path.isdir(subsystem_path)
|
||||
root_dir = None
|
||||
root_xml = None
|
||||
|
||||
if is_dir:
|
||||
root_dir = subsystem_path
|
||||
else:
|
||||
if not os.path.isfile(subsystem_path):
|
||||
print(f"[ERROR] File not found: {subsystem_path}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
root_xml = subsystem_path
|
||||
|
||||
# Box-drawing chars
|
||||
T_BRANCH = "\u251C\u2500\u2500 " # ├──
|
||||
T_LAST = "\u2514\u2500\u2500 " # └──
|
||||
T_PIPE = "\u2502 " # │
|
||||
T_ARROW = "\u2192" # →
|
||||
|
||||
def get_tree_line(xml_path):
|
||||
parsed = load_subsystem_xml(xml_path)
|
||||
sub = parsed["Sub"]
|
||||
props = sub.find("md:Properties", NS)
|
||||
name_node = props.find("md:Name", NS)
|
||||
name = name_node.text if name_node is not None else ""
|
||||
|
||||
markers = []
|
||||
sub_dir = get_subsystem_dir(xml_path)
|
||||
ci_path = os.path.join(sub_dir, "Ext", "CommandInterface.xml")
|
||||
if os.path.isfile(ci_path):
|
||||
markers.append("CI")
|
||||
use_one = props.find("md:UseOneCommand", NS)
|
||||
if use_one is not None and use_one.text == "true":
|
||||
markers.append("OneCmd")
|
||||
incl_ci_node = props.find("md:IncludeInCommandInterface", NS)
|
||||
if incl_ci_node is not None and incl_ci_node.text == "false":
|
||||
markers.append("Скрыт")
|
||||
marker_str = f" [{', '.join(markers)}]" if markers else ""
|
||||
|
||||
content_items = get_content_items(props)
|
||||
child_names = get_child_names(sub)
|
||||
child_str = f", {len(child_names)} дочерних" if child_names else ""
|
||||
|
||||
return {
|
||||
"Label": f"{name}{marker_str} ({len(content_items)} объектов{child_str})",
|
||||
"SubDir": sub_dir,
|
||||
"ChildNames": child_names,
|
||||
}
|
||||
|
||||
def build_tree_entry(xml_path, prefix, is_last, is_root):
|
||||
info = get_tree_line(xml_path)
|
||||
|
||||
if is_root:
|
||||
connector = ""
|
||||
elif is_last:
|
||||
connector = T_LAST
|
||||
else:
|
||||
connector = T_BRANCH
|
||||
out(f"{prefix}{connector}{info['Label']}")
|
||||
|
||||
if info["ChildNames"]:
|
||||
if is_root:
|
||||
child_prefix = ""
|
||||
elif is_last:
|
||||
child_prefix = prefix + " "
|
||||
else:
|
||||
child_prefix = prefix + T_PIPE
|
||||
|
||||
subs_dir = os.path.join(info["SubDir"], "Subsystems")
|
||||
for i, child_name in enumerate(info["ChildNames"]):
|
||||
child_xml = os.path.join(subs_dir, f"{child_name}.xml")
|
||||
child_is_last = (i == len(info["ChildNames"]) - 1)
|
||||
if os.path.isfile(child_xml):
|
||||
build_tree_entry(child_xml, child_prefix, child_is_last, False)
|
||||
else:
|
||||
conn2 = T_LAST if child_is_last else T_BRANCH
|
||||
out(f"{child_prefix}{conn2}{child_name} [NOT FOUND]")
|
||||
|
||||
if root_dir:
|
||||
label = os.path.basename(root_dir)
|
||||
out(f"Дерево подсистем от: {label}/")
|
||||
out()
|
||||
xml_files = sorted(
|
||||
[f for f in os.listdir(root_dir) if f.lower().endswith(".xml") and os.path.isfile(os.path.join(root_dir, f))],
|
||||
key=lambda x: x.lower()
|
||||
)
|
||||
if args.Name:
|
||||
xml_files = [f for f in xml_files if os.path.splitext(f)[0] == args.Name]
|
||||
if not xml_files:
|
||||
print(f"[ERROR] Subsystem '{args.Name}' not found in {root_dir}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
for i, fname in enumerate(xml_files):
|
||||
build_tree_entry(os.path.join(root_dir, fname), "", i == len(xml_files) - 1, True)
|
||||
else:
|
||||
build_tree_entry(root_xml, "", True, True)
|
||||
|
||||
elif args.Mode == "ci":
|
||||
# ============================================================
|
||||
# Mode: ci -- CommandInterface.xml
|
||||
# ============================================================
|
||||
if os.path.isdir(subsystem_path):
|
||||
print("[ERROR] ci mode requires a subsystem .xml file, not a directory", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
# File not found -- check Dir/Name/Name.xml -> Dir/Name.xml
|
||||
if not os.path.isfile(subsystem_path):
|
||||
fn = os.path.splitext(os.path.basename(subsystem_path))[0]
|
||||
pd = os.path.dirname(subsystem_path)
|
||||
if fn == os.path.basename(pd):
|
||||
c = os.path.join(os.path.dirname(pd), f"{fn}.xml")
|
||||
if os.path.isfile(c):
|
||||
subsystem_path = c
|
||||
if not os.path.isfile(subsystem_path):
|
||||
print(f"[ERROR] File not found: {subsystem_path}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
parsed = load_subsystem_xml(subsystem_path)
|
||||
sub = parsed["Sub"]
|
||||
props = sub.find("md:Properties", NS)
|
||||
name_node = props.find("md:Name", NS)
|
||||
sub_name = name_node.text if name_node is not None else ""
|
||||
|
||||
show_ci(sub_name, subsystem_path)
|
||||
|
||||
else:
|
||||
# ============================================================
|
||||
# Mode: overview / content / full -- requires a subsystem XML file
|
||||
# ============================================================
|
||||
if os.path.isdir(subsystem_path):
|
||||
dir_name = os.path.basename(subsystem_path)
|
||||
candidate = os.path.join(subsystem_path, f"{dir_name}.xml")
|
||||
sibling = os.path.join(os.path.dirname(subsystem_path), f"{dir_name}.xml")
|
||||
if os.path.isfile(candidate):
|
||||
subsystem_path = candidate
|
||||
elif os.path.isfile(sibling):
|
||||
subsystem_path = sibling
|
||||
else:
|
||||
print(f"[ERROR] No {dir_name}.xml found in directory. Use -Mode tree for directory listing.", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
# File not found -- check Dir/Name/Name.xml -> Dir/Name.xml
|
||||
if not os.path.isfile(subsystem_path):
|
||||
fn = os.path.splitext(os.path.basename(subsystem_path))[0]
|
||||
pd = os.path.dirname(subsystem_path)
|
||||
if fn == os.path.basename(pd):
|
||||
c = os.path.join(os.path.dirname(pd), f"{fn}.xml")
|
||||
if os.path.isfile(c):
|
||||
subsystem_path = c
|
||||
if not os.path.isfile(subsystem_path):
|
||||
print(f"[ERROR] File not found: {subsystem_path}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
parsed = load_subsystem_xml(subsystem_path)
|
||||
sub = parsed["Sub"]
|
||||
props = sub.find("md:Properties", NS)
|
||||
|
||||
name_node = props.find("md:Name", NS)
|
||||
sub_name = name_node.text if name_node is not None else ""
|
||||
synonym = get_ml_text(props.find("md:Synonym", NS))
|
||||
comment_node = props.find("md:Comment", NS)
|
||||
comment_text = comment_node.text if comment_node is not None and comment_node.text else ""
|
||||
incl_help_node = props.find("md:IncludeHelpInContents", NS)
|
||||
incl_help = incl_help_node.text if incl_help_node is not None else ""
|
||||
incl_ci_node = props.find("md:IncludeInCommandInterface", NS)
|
||||
incl_ci = incl_ci_node.text if incl_ci_node is not None else ""
|
||||
use_one_cmd_node = props.find("md:UseOneCommand", NS)
|
||||
use_one_cmd = use_one_cmd_node.text if use_one_cmd_node is not None else ""
|
||||
explanation = get_ml_text(props.find("md:Explanation", NS))
|
||||
|
||||
# Picture
|
||||
pic_node = props.find("md:Picture", NS)
|
||||
pic_text = ""
|
||||
if pic_node is not None and len(pic_node) > 0:
|
||||
pic_ref = pic_node.find("xr:Ref", NS)
|
||||
if pic_ref is not None and pic_ref.text:
|
||||
pic_text = pic_ref.text
|
||||
|
||||
# Content
|
||||
content_items = get_content_items(props)
|
||||
groups = group_content_by_type(content_items)
|
||||
|
||||
# Children
|
||||
child_names = get_child_names(sub)
|
||||
|
||||
# CI presence
|
||||
sub_dir = get_subsystem_dir(subsystem_path)
|
||||
ci_path = os.path.join(sub_dir, "Ext", "CommandInterface.xml")
|
||||
has_ci = os.path.isfile(ci_path)
|
||||
|
||||
if args.Mode == "overview":
|
||||
show_overview(sub_name, synonym, comment_text, incl_ci, use_one_cmd,
|
||||
explanation, pic_text, content_items, groups, child_names, has_ci)
|
||||
elif args.Mode == "content":
|
||||
show_content(sub_name, content_items, groups, args.Name)
|
||||
elif args.Mode == "full":
|
||||
show_overview(sub_name, synonym, comment_text, incl_ci, use_one_cmd,
|
||||
explanation, pic_text, content_items, groups, child_names, has_ci)
|
||||
out()
|
||||
out("--- content ---")
|
||||
out()
|
||||
show_content(sub_name, content_items, groups, args.Name)
|
||||
out()
|
||||
out("--- ci ---")
|
||||
out()
|
||||
show_ci(sub_name, subsystem_path)
|
||||
|
||||
# --- Pagination and output ---
|
||||
total_lines = len(lines_buf)
|
||||
out_lines = lines_buf[:]
|
||||
|
||||
if args.Offset > 0:
|
||||
if args.Offset >= total_lines:
|
||||
print(f"[INFO] Offset {args.Offset} exceeds total lines ({total_lines}). Nothing to show.")
|
||||
sys.exit(0)
|
||||
out_lines = out_lines[args.Offset:]
|
||||
|
||||
if args.Limit > 0 and len(out_lines) > args.Limit:
|
||||
shown = out_lines[:args.Limit]
|
||||
remaining = total_lines - args.Offset - args.Limit
|
||||
shown.append("")
|
||||
shown.append(f"[ОБРЕЗАНО] Показано {args.Limit} из {total_lines} строк. Используйте -Offset {args.Offset + args.Limit} для продолжения.")
|
||||
out_lines = shown
|
||||
|
||||
if args.OutFile:
|
||||
out_file = args.OutFile
|
||||
if not os.path.isabs(out_file):
|
||||
out_file = os.path.join(os.getcwd(), out_file)
|
||||
with open(out_file, "w", encoding="utf-8-sig") as f:
|
||||
f.write("\n".join(out_lines))
|
||||
print(f"Output written to {out_file}")
|
||||
else:
|
||||
for line in out_lines:
|
||||
print(line)
|
||||
Reference in New Issue
Block a user