path_utils 0.0.1 copy "path_utils: ^0.0.1" to clipboard
path_utils: ^0.0.1 copied to clipboard

Cross-platform path resolution and subprocess environment utilities. Resolves GUI-app PATH gaps, finds executables, and runs commands with a shell-aware environment.

example/lib/main.dart

import 'package:flutter/material.dart';

import 'path_utils_demo.dart';

void main() {
  runApp(const PathUtilsExampleApp());
}

class PathUtilsExampleApp extends StatelessWidget {
  const PathUtilsExampleApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'path_utils example',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(
          seedColor: Colors.teal,
          brightness: Brightness.light,
        ),
        useMaterial3: true,
      ),
      darkTheme: ThemeData(
        colorScheme: ColorScheme.fromSeed(
          seedColor: Colors.teal,
          brightness: Brightness.dark,
        ),
        useMaterial3: true,
      ),
      themeMode: ThemeMode.system,
      home: const DemoPage(),
    );
  }
}

class DemoPage extends StatefulWidget {
  const DemoPage({super.key});

  @override
  State<DemoPage> createState() => _DemoPageState();
}

class _DemoPageState extends State<DemoPage> {
  late Future<List<String>> _demoLines;
  final _executableController = TextEditingController();
  final _lookupHistory = <_LookupResult>[];
  bool _lookupInProgress = false;

  @override
  void initState() {
    super.initState();
    _demoLines = runPathUtilsDemo();
  }

  @override
  void dispose() {
    _executableController.dispose();
    super.dispose();
  }

  void _refreshDemo() {
    setState(() {
      _demoLines = runPathUtilsDemo();
    });
  }

  Future<void> _lookupExecutable() async {
    final name = _executableController.text.trim();
    if (name.isEmpty || _lookupInProgress) {
      return;
    }

    setState(() => _lookupInProgress = true);

    try {
      final path = await lookupExecutable(name);
      if (!mounted) {
        return;
      }

      setState(() {
        _lookupHistory.insert(
          0,
          _LookupResult(name: name, path: path),
        );
      });
    } finally {
      if (mounted) {
        setState(() => _lookupInProgress = false);
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('path_utils example'),
        actions: [
          IconButton(
            onPressed: _refreshDemo,
            tooltip: 'Run demo again',
            icon: const Icon(Icons.refresh),
          ),
        ],
      ),
      body: ListView(
        padding: const EdgeInsets.all(16),
        children: [
          Text(
            'Resolved paths and subprocess environment',
            style: Theme.of(context).textTheme.titleMedium,
          ),
          const SizedBox(height: 12),
          FutureBuilder<List<String>>(
            future: _demoLines,
            builder: (context, snapshot) {
              if (snapshot.connectionState != ConnectionState.done) {
                return const Padding(
                  padding: EdgeInsets.symmetric(vertical: 24),
                  child: Center(child: CircularProgressIndicator()),
                );
              }

              if (snapshot.hasError) {
                return Text('Error: ${snapshot.error}');
              }

              final lines = snapshot.data ?? const <String>[];
              return SelectableText(
                lines.join('\n'),
                style: Theme.of(context).textTheme.bodyMedium?.copyWith(
                  fontFamily: 'monospace',
                ),
              );
            },
          ),
          const SizedBox(height: 24),
          const Divider(),
          const SizedBox(height: 16),
          Text(
            'Find an executable',
            style: Theme.of(context).textTheme.titleMedium,
          ),
          const SizedBox(height: 8),
          Text(
            isExecutableLookupAvailable
                ? 'Search the comprehensive PATH for any binary name.'
                : 'Executable lookup requires a desktop platform (dart:io).',
            style: Theme.of(context).textTheme.bodyMedium,
          ),
          const SizedBox(height: 12),
          Row(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Expanded(
                child: TextField(
                  controller: _executableController,
                  enabled: isExecutableLookupAvailable && !_lookupInProgress,
                  decoration: const InputDecoration(
                    labelText: 'Executable name',
                    hintText: 'e.g. git, java, npm',
                    border: OutlineInputBorder(),
                  ),
                  textInputAction: TextInputAction.search,
                  onSubmitted: isExecutableLookupAvailable ? (_) => _lookupExecutable() : null,
                ),
              ),
              const SizedBox(width: 12),
              FilledButton.icon(
                onPressed: isExecutableLookupAvailable && !_lookupInProgress ? _lookupExecutable : null,
                icon: _lookupInProgress
                    ? const SizedBox(
                        width: 18,
                        height: 18,
                        child: CircularProgressIndicator(strokeWidth: 2),
                      )
                    : const Icon(Icons.search),
                label: const Text('Find'),
              ),
            ],
          ),
          if (_lookupHistory.isNotEmpty) ...[
            const SizedBox(height: 16),
            Text(
              'Lookup results',
              style: Theme.of(context).textTheme.titleSmall,
            ),
            const SizedBox(height: 8),
            ..._lookupHistory.map(_LookupResultTile.new),
          ],
        ],
      ),
      floatingActionButton: FloatingActionButton.extended(
        onPressed: _refreshDemo,
        icon: const Icon(Icons.play_arrow),
        label: const Text('Run demo'),
      ),
    );
  }
}

class _LookupResult {
  const _LookupResult({required this.name, required this.path});

  final String name;
  final String? path;
}

class _LookupResultTile extends StatelessWidget {
  const _LookupResultTile(this.result);

  final _LookupResult result;

  @override
  Widget build(BuildContext context) {
    final found = result.path != null;
    final colorScheme = Theme.of(context).colorScheme;

    return Card(
      margin: const EdgeInsets.only(bottom: 8),
      child: ListTile(
        leading: Icon(
          found ? Icons.check_circle_outline : Icons.cancel_outlined,
          color: found ? colorScheme.primary : colorScheme.error,
        ),
        title: Text(result.name),
        subtitle: SelectableText(
          found ? result.path! : 'Not found on comprehensive PATH',
          style: Theme.of(context).textTheme.bodyMedium?.copyWith(
            fontFamily: 'monospace',
          ),
        ),
      ),
    );
  }
}
1
likes
160
points
58
downloads

Documentation

API reference

Publisher

verified publishergantt-sync.com

Weekly Downloads

Cross-platform path resolution and subprocess environment utilities. Resolves GUI-app PATH gaps, finds executables, and runs commands with a shell-aware environment.

Repository (GitHub)
View/report issues

Topics

#path #process #shell #utilities

License

MIT (license)

Dependencies

path

More

Packages that depend on path_utils