Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
B
book
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Container Registry
Model registry
Operate
Environments
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
redox-os
book
Commits
9a74fea3
Commit
9a74fea3
authored
8 years ago
by
jeff
Browse files
Options
Downloads
Patches
Plain Diff
Update shell.md
parent
10e9ce75
No related branches found
No related tags found
1 merge request
!43
Update shell.md
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
src/explore/shell.md
+122
-0
122 additions, 0 deletions
src/explore/shell.md
with
122 additions
and
0 deletions
src/explore/shell.md
+
122
−
0
View file @
9a74fea3
# Shell
# Shell
ion is the
[
shell
](
http://linuxcommand.org/lts0010.php
)
used in redox.
when the shell is call without "-c", it start a main loop
which can be found inside
`Shell.execute()`
```
Rust
self.print_prompt();
while let Some(command) = readln() {
let command = command.trim();
if !command.is_empty() {
self.on_command(command, &commands);
}
self.update_variables();
self.print_prompt();
}
```
`self.print_prompt();`
is used to print the shell prompt.
the
`readln()`
is a the input reader which code can be found in
`crates/ion/src/input_editor`
The documentation about trim can be found
[
here
](
https://doc.rust-lang.org/std/primitive.str.html#method.trim
)
.
if the commands is not empty, the method
`on_command`
will be called. this method will be developed later.
then the shell will update variables, and reprint the prompt.
```
Rust
fn on_command(&mut self, command_string: &str, commands: &HashMap<&str, Command>) {
self.history.add(command_string.to_string(), &self.variables);
let mut pipelines = parse(command_string);
// Execute commands
for pipeline in pipelines.drain(..) {
if self.flow_control.collecting_block {
// TODO move this logic into "end" command
if pipeline.jobs[0].command == "end" {
self.flow_control.collecting_block = false;
let block_jobs: Vec<Pipeline> = self.flow_control
.current_block
.pipelines
.drain(..)
.collect();
match self.flow_control.current_statement.clone() {
Statement::For(ref var, ref vals) => {
let variable = var.clone();
let values = vals.clone();
for value in values {
self.variables.set_var(&variable, &value);
for pipeline in &block_jobs {
self.run_pipeline(&pipeline, commands);
}
}
},
Statement::Function(ref name, ref args) => {
self.functions.insert(name.clone(), Function { name: name.clone(), pipelines: block_jobs.clone(), args: args.clone() });
},
_ => {}
}
self.flow_control.current_statement = Statement::Default;
} else {
self.flow_control.current_block.pipelines.push(pipeline);
}
} else {
if self.flow_control.skipping() && !is_flow_control_command(&pipeline.jobs[0].command) {
continue;
}
self.run_pipeline(&pipeline, commands);
}
}
}
```
the first thing the
`on_command`
does it to add the commands into the history with
`self.history.add(command_string.to_string(), &self.variables);`
.
Then the script will be parse. the parser code is in
`crates/ion/src/peg.rs`
the parse will return a set of pipelines, each pipeline contains a set of jobs.
Each job represents a single command with its arguments.
you can take a look in
`crates/ion/src/peg.rs`
```
Rust
pub struct Pipeline {
pub jobs: Vec<Job>,
pub stdout: Option<Redirection>,
pub stdin: Option<Redirection>,
}
pub struct Job {
pub command: String,
pub args: Vec<String>,
pub background: bool,
}
```
what will happen after is in brief :
*
if the current block is a collecting block (a for loop or a function declaration) and the current command is end, we close the block:
*
if the block is a for loop we run the loop
*
if the block is a function declaration we push the function to the functions list
*
If the current block is a collecting block but the current command is not end, we add the current command to the block.
*
If the current block is not a collecting block, we simply execute the current command.
the code blocks are defined in
`crates/ion/src/flow_control.rs`
```
Rust
pub struct CodeBlock {
pub pipelines: Vec<Pipeline>,
}
```
the function code is defined in
`crates/ion/src/functions.rs`
the execution of pipeline content will be executer in
`run_pipeline()`
the Command class inside
`crates/ion/src/main.rs`
maps each command with an description and a method
to be executed. for example :
```
Rust
commands.insert("cd",
Command {
name: "cd",
help: "Change the current directory\n cd <path>",
main: box |args: &[String], shell: &mut Shell| -> i32 {
shell.directory_stack.cd(args, &shell.variables)
},
});
```
`cd`
is described by
`"Change the current directory\n cd <path>"`
, and when called the method
`shell.directory_stack.cd(args, &shell.variables)`
will be used. you can see its code in
`crates/ion/src/directory_stack.rs`
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment