Skip to content
Snippets Groups Projects
Commit 7645ee7c authored by Torstein Strømme's avatar Torstein Strømme
Browse files

flere kommentarer, noen klargjøringer

parent 50bdee5c
No related branches found
No related tags found
No related merge requests found
......@@ -5,16 +5,12 @@ I denne lab'en skal vi utforske *grensesnitt*, og fortsette med å benytte oss a
Samtidig skal vi benytte anledningen til å bli bedre kjent med terminalen, som er et svært viktig verktøy for alle som jobber teknisk med datamaskiner. Både utviklere, system-adminstratorer og vanlige brukere som ønsker å benytte spesialisert software andre har laget vil ha stor glede av den.
> Kjært barn har mange navn. Under lister vi opp noen synonymer til «terminal» med litt ulike opphav, og som har litt ulike konnotasjoner. I praksis bruker vi disse ordene litt om hverandre.
> * **Terminal**. Opprinnelig brukt om kombinasjonen av en fysisk skjerm og et tastatur. Disse kunne være et annet sted enn selve datamaskinen. I senere tid har begrepet blitt brukt om programmer som gir et grafisk brukergrensesnitt (et vindu) til et shell. En **konsoll** var en spesiell terminal som var en integrert del av datamaskinen, og som ikke kunne skilles fra den slik man kunne med andre terminaler.
> * **Shell**. Programmet som vanligvis vises i en terminal. Dette er et rent software-konsept. Et shell *tolker* kommandoer og kan starte andre prosesser. Opprinnelig var dette det dataprogrammet som startet først når oppstarten var ferdig og datamaskinen var klar til bruk. Det ble kalt et shell fordi det «omgav» kjernen i operativsystemet som et skall, og ble for brukerne det eneste de trengte å forholde seg til ved bruk av maskinen. Ordet kommer naturligvis fra tiden før vinduer og mus var vanlig. Det finnes mange ulike shell: for eksempel er **bash** og **zsh** i dag vanlige shell for Linux/Mac mens **cmd** og **PowerShell** er vanlige shell i Windows.
> * **CLI** (kommandolinjen). Et CLI (*command line interface*) er et program med et tekstbasert grensesnitt, for eksempel et shell. Men en kommandolinje er ikke nødvendigvis knyttet til å navigere et operativsystem og starte andre programmer. For eksempel kan vi lage et tekstbasert spill; dette spillet vil da ha en kommandolinje selv om vi ikke ville kalt det for et shell.
I denne lab'en skal vi lage et enkelt shell for å navigere filsystemet som er løst inspirert av *bash*. Kommandoene vi bruker vil også fungere omtrent på samme måte i zsh og PowerShell.
I denne lab'en skal vi modifisere et enkelt shell for å navigere filsystemet som er løst inspirert av *bash*. Kommandoene vi bruker vil også fungere omtrent på samme måte i zsh og PowerShell.
## Oversikt
* [Bakgrunn: shell og terminal](#bakgrunn--shell-og-terminal)
* [Bli kjent med eksisterende kildekode](#bli-kjent-med-eksisterende-kildekode)
* [Kjøre SimpleShell](#kjøre-simpleshell)
* [Vis SimpleShell gjennom GUI](#vis-simpleshell-gjennom-gui)
......@@ -34,6 +30,13 @@ I denne lab'en skal vi lage et enkelt shell for å navigere filsystemet som er l
* [grep: en bonus-utfordring](#grep--en-bonus-utfordring)
## Bakgrunn: shell og terminal
Kjært barn har mange navn. Under lister vi opp noen synonymer til «terminal» med litt ulike opphav, og som har litt ulike konnotasjoner. I praksis bruker vi disse ordene litt om hverandre.
* **Terminal**. Opprinnelig brukt om kombinasjonen av en fysisk skjerm og et tastatur. Disse kunne være et annet sted enn selve datamaskinen. I senere tid har begrepet blitt brukt om programmer som gir et grafisk brukergrensesnitt (et vindu) til et shell. En **konsoll** var en spesiell terminal som var en integrert del av datamaskinen, og som ikke kunne skilles fra den slik man kunne med andre terminaler.
* **Shell**. Programmet som vanligvis vises i en terminal. Dette er et rent software-konsept. Et shell *tolker* kommandoer og kan starte andre prosesser. Opprinnelig var dette det dataprogrammet som startet først når oppstarten var ferdig og datamaskinen var klar til bruk. Det ble kalt et shell fordi det «omgav» kjernen i operativsystemet som et skall, og ble for brukerne det eneste de trengte å forholde seg til ved bruk av maskinen. Ordet kommer naturligvis fra tiden før vinduer og mus var vanlig. Det finnes mange ulike shell: for eksempel er **bash** og **zsh** i dag vanlige shell for Linux/Mac mens **cmd** og **PowerShell** er vanlige shell i Windows.
* **CLI** (kommandolinjen). Et CLI (*command line interface*) er et program med et tekstbasert grensesnitt, for eksempel et shell. Men en kommandolinje er ikke nødvendigvis knyttet til å navigere et operativsystem og starte andre programmer. For eksempel kan vi lage et tekstbasert spill; dette spillet vil da ha en kommandolinje selv om vi ikke ville kalt det for et shell.
## Bli kjent med eksisterende kildekode
- [ ] Kjør *main*-metoden i `Main` ([link](./src/main/java/no/uib/inf101/terminal/Main.java)) og se at du får opp et vindu du kan skrive i. Sjekk at det virker å skrive, og at du får en ny linje når du trykker enter.
......@@ -52,6 +55,11 @@ I resten av oppgaven skal vi modifisere klassen [SimpleShell](./src/main/java/no
- [ ] Kjør testene i `TestSimpleShellStarter` ([link](./src/test/java/no/uib/inf101/terminal/TestSimpleShellStarter.java)) og se at de allerede passerer.
> **Målet med laben.** Før vi gjør noen endringer i det hele tatt, støtter SimpleShell tre kommandoer: pwd, ls og cd. I løpet av laben skal vi oppdatere SimpleShell slik at
> * det virker sammen med GUI'en vår «Terminal», og
> * shellet virker med ubegrenset mange kommandoer.
>
> Når laben er gjennomførst skal vi kunne installere så mange kommandoer vi vil i SimpleShell uten å endre mer på kildekoden i SimpleShell-klassen.
### Vis SimpleShell gjennom GUI
Vi ønsker at det grafiske brukergrensesnittet vårt [Terminal](./src/main/java/no/uib/inf101/terminal/Terminal.java) skal virke sammen med SimpleShell. Konsturktøren til Terminal-klassen aksepterer alle shell og objekter som implementerer *CommandLineInterface*.
......@@ -91,7 +99,7 @@ Som pseudokode kan koden over tolkes slik:
* Basert på verdien av `commandName`, finn ut hvilken kommando som skal utføres
* Dersom vi fant en gyldig kommando, utfør den og returner resultatet.
Du trenger ikke å ender denne koden helt enda, men dette illustrer hvor vi er på vei. For å komme oss hit, mangler vi en del ting. For eksempel finnes det ikke en type som heter `Command`. La oss definer den nå:
Du trenger ikke å ender denne koden helt enda, men dette illustrer hvor vi er på vei. For å komme oss hit, mangler vi en del ting. For eksempel finnes det ikke en type som heter `Command`. La oss definere den nå:
### Opprette grensesnittet `Command`
......@@ -157,7 +165,7 @@ Koden over oppretter en variabel som
* heter `allCommands`, og
* har typen `HashMap<String, Command>`. Det betyr at typen er et oppslagsverk hvor nøklene er av typen `String`, og verdiene er av typen `Command`.
I tillegg opprettes det et nytt objekt i klassen `HashMap` som da er et tomt oppslagsverk uten noen nøkler eller verdier enda. Det neste vi skal gjøre er å gjøre det mulig å legge til kommandoer i oppslagsverket.
I tillegg opprettes det et nytt objekt i klassen `HashMap` som ved opprettelse er et tomt oppslagsverk uten noen nøkler eller verdier enda. Det neste vi skal gjøre er å gjøre det mulig å legge til kommandoer i oppslagsverket.
- [ ] Opprett en metode i SimpleShell med signatur `public void installCommand(Command)`. La metoden hente ut navnet fra Command -objektet og opprett et nytt nøkkel-verdi -par i *allCommands* med navnet som nøkkel og Command-objektet som verdi. For eksempel:
......
package no.uib.inf101.terminal;
// UiB INF101 ShellLab - CommandLineInterface.java
//
// Grensesnittet CommanLineInterface beskriver metoder for input og
// output til et program som virker med et tekstbasert grensesnitt.
// Du trenger ikke gjøre noen endringer i denne filen for denne lab'en.
/**
* A command line interface is a program with a text-based user interface.
* The user can enter keys as input, and the program will respond by giving
......@@ -10,13 +16,14 @@ public interface CommandLineInterface {
/**
* Called when a key is pressed.
*
* @param key The key that was pressed
* @param key the key that was pressed
*/
void keyPressed(char key);
/**
* Get the text to display on the screen.
* @return The text to display
*
* @return the text to display
*/
String getScreenContent();
}
package no.uib.inf101.terminal;
// UiB INF101 ShellLab - Context.java
//
// Denne filen inneholder kode som navigerer et filsystem. Du trenger
// ikke gjøre noen endringer i denne filen for denne lab'en (med mindre
// du selv ønsker).
import java.io.File;
import java.io.IOException;
import java.util.Objects;
public class Context {
////////////////////////
// Instance variables
////////////////////////
private final File home;
private File cwd;
////////////////////////
// Constructors
////////////////////////
/**
* Create a new context with the java current working directory as
* home.
*/
public Context() {
this(new File(System.getProperty("user.dir")));
}
/**
* Create a new context with the given directory as home.
*
* @param home the home directory.
*/
public Context(File home) {
try {
this.home = home.getCanonicalFile();
......@@ -18,27 +44,50 @@ public class Context {
}
}
////////////////////////
// Instance methods
////////////////////////
/**
* Go to the given path, if it exists. The path can be relative to
* the current working directory, or absolute.
*
* @param path the path to go to.
* @return true if the path exists, false otherwise
*/
public boolean goToPath(String path) {
File newDir = new File(cwd, path);
File newDir = new File(this.cwd, path);
if (!newDir.isDirectory()) {
return false;
}
try {
cwd = newDir.getCanonicalFile();
this.cwd = newDir.getCanonicalFile();
return true;
} catch (IOException e) {
throw new RuntimeException(e);
}
return true;
}
/**
* Get the current working directory.
*
* @return the current working directory.
*/
public File getCwd() {
return this.cwd;
}
/** Set the current working directory to the home directory.*/
public void goToHome() {
this.cwd = this.home;
}
/**
* Check if the current working directory is the home directory.
*
* @return true if the current working directory is the home
* directory, false otherwise.
*/
public boolean isAtHome() {
return Objects.equals(this.cwd, this.home);
}
......
package no.uib.inf101.terminal;
// UiB INF101 ShellLab - DynamicShell.java
//
// Denne koden er gitt som et eksempel på en klasse som implementerer
// CommanLineInterface. Du trenger ikke gjøre noen endringer i denne
// filen for denne lab'en (med mindre du selv ønsker).
public class DummyShell implements CommandLineInterface {
private String screenContent = "$ ";
......
package no.uib.inf101.terminal;
// UiB INF101 ShellLab - EchoShell.java
//
// Denne koden er gitt som et eksempel på en klasse som implementerer
// CommanLineInterface. Du trenger ikke gjøre noen endringer i denne
// filen for denne lab'en (med mindre du selv ønsker).
import java.util.ArrayList;
public class EchoShell implements CommandLineInterface {
......
package no.uib.inf101.terminal;
// UiB INF101 ShellLab - Main.java
// Dette er filen som inneholder main-metoden.
public class Main {
public static void main(String[] args) {
......
package no.uib.inf101.terminal;
// UiB INF101 ShellLab - SimpleShell.java
//
// Dette er klassen vi skal forbedre i denne lab'en. Slik koden er
// allerede før du begynner på laben, støtter den tre kommandoer:
//
// - cd: Bytt til en annen mappe
// - ls: List opp filer i mappen
// - pwd: Vis sti til nåværende mappe
//
// Vi skal endre denne klassen slik at den
// - kan vises av Terminal.java
// - kan støtte ubegrenset mange kommandoer
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
// TODO: Let SimpleShell implement CommandLineInterface
// TODO 1: Let SimpleShell implement CommandLineInterface
public class SimpleShell {
//////////////////////////////////////////////////////////////////////
......@@ -14,24 +28,24 @@ public class SimpleShell {
/** The prompt to show before each command */
private final String prompt = "$ ";
/** The context variable contains cwd and home directories etc. */
private final Context context = new Context(
new File(System.getProperty("user.dir"))
);
private final Context context = new Context();
/** A list of historic commands and their outputs */
private final ArrayList<String> history = new ArrayList<>();
private final List<String> history = new ArrayList<>();
/** The command currently being typed */
private String currentCommand = "";
// TODO 4: Create instance variable storing Command objects
//////////////////////////////////////////////////////////////////////
/// Public methods //////
/// Public instance methods //////
/// (methods expected to be used by someone outside this class) //////
//////////////////////////////////////////////////////////////////////
/** Constructor for SimpleShell */
public SimpleShell() {
// TODO: Install core commands SimpleShell supports (pwd, ls, cd)
// TODO 7-8-9: Install core commands SimpleShell supports (pwd, ls, cd)
}
// TODO: rename method to fit new interface, annotate with @Override
// TODO 2: rename method to fit new interface, annotate with @Override
// Note: methods with @Override generally do not need javadoc comments,
// since the javadoc comment is inherited. You should hence remove the
// javadoc comment here unless there is something special about this
......@@ -49,7 +63,7 @@ public class SimpleShell {
}
}
// TODO: rename method to fit new interface, annotate with @Override
// TODO 3: rename method to fit new interface, annotate with @Override
/**
* Get the text which the terminal should display
*
......@@ -65,6 +79,13 @@ public class SimpleShell {
return s;
}
/** Get the context of this shell */
public Context getContext() {
return this.context;
}
// TODO 5: Add method to install a command
//////////////////////////////////////////////////////////////////////
/// Private methods ///////////////////
/// (helper methods used internally in this class) ///////////////////
......@@ -102,7 +123,8 @@ public class SimpleShell {
* @return The output of the command
*/
private String executeCommand(String commandName, String[] args) {
// TODO: Change sequence of if/else if below to a lookup in a map
// TODO 6: Call run on Command object for given commandName if present
// TODO 7-8-9: Remove if's for cd, ls, pwd once installed as commands
if (Objects.equals(commandName, "pwd")) {
return this.doPwd(args);
} else if (Objects.equals(commandName, "cd")) {
......@@ -114,12 +136,12 @@ public class SimpleShell {
}
}
// TODO: remove this method and replace it with Command -type object
// TODO 7: remove this method and replace it with Command -type object
private String doPwd(String[] args) {
return this.context.getCwd().getAbsolutePath();
}
// TODO: remove this method and replace it with Command -type object
// TODO 8: remove this method and replace it with Command -type object
private String doCd(String[] args) {
if (args.length == 0) {
this.context.goToHome();
......@@ -135,7 +157,7 @@ public class SimpleShell {
}
}
// TODO: remove this method and replace it with Command -type object
// TODO 9: remove this method and replace it with Command -type object
private String doLs(String[] args) {
File cwd = this.context.getCwd();
String s = "";
......
package no.uib.inf101.terminal;
// UiB INF101 ShellLab - Terminal.java
//
// Denne filen inneholder kode som tegner et vindu på skjermen, som
// viser et CommandLineInterface -program. Du er ikke forventet å
// forstå denne koden denne uken, og du trenger ikke gjøre noen
// endringer i denne filen for denne lab'en (med mindre du selv ønsker).
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
/**
* A simple terminal GUI for interacting with command line interfaces.
*/
public class Terminal extends JPanel {
private final CommandLineInterface terminal;
////////////////////////
// Instance variables
////////////////////////
/** The command line interface to interact with. */
private final CommandLineInterface cli;
////////////////////////
// Constructor
////////////////////////
/** Create a new terminal GUI for the given command line interface. */
public Terminal(CommandLineInterface cli) {
this.terminal = cli;
this.cli = cli;
this.setPreferredSize(new Dimension(400, 300));
this.setFocusable(true);
this.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
Terminal.this.terminal.keyPressed(e.getKeyChar());
Terminal.this.cli.keyPressed(e.getKeyChar());
Terminal.this.repaint();
}
});
}
////////////////////////
// Instance methods
////////////////////////
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
String content = this.terminal.getScreenContent();
// Calculate number of lines that can fit display
int lineHeight = g.getFontMetrics().getHeight() + 5;
int lines = this.getHeight() / lineHeight;
// Draw the text on the screen, line by line
g.setColor(Color.BLACK);
g.setFont(new Font("Monospaced", Font.PLAIN, 12));
int y = lineHeight;
int lineHeight = g.getFontMetrics().getHeight() + 2;
// Iterate through the last 'lines' lines of the content
String[] linesOfContent = content.split("\n");
for (int i = Math.max(0, linesOfContent.length - lines); i < linesOfContent.length; i++) {
g.drawString(linesOfContent[i], 5, y);
// Tegn teksten på skjermen, linje for linje. Potensiell forbedring:
// hvis det er for mange linjer, vis kun de siste av dem.
String content = this.cli.getScreenContent();
int y = 20;
for (String line : content.split("\n")) {
g.drawString(line, 5, y);
y += lineHeight;
}
}
/** Run the terminal GUI in a window frame. */
public void run() {
JFrame frame = new JFrame("INF101 Terminal");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
......
package no.uib.inf101.terminal;
// UiB INF101 ShellLab - TextAnswers.java
//
// I denne filen skal du besvare spørsmålene under. Du kan sjekke
// svarene dine ved å kjøre testen TextAnswersTest.java.
public class TextAnswers {
/*
/**
* Consider the following code:
*
* CommandLineInterface cli = new DummyShell();
*
* What is the type of the variable cli?
*/
/** What is the type of the variable cli? */
static final String q1 = "";
/** In which class is the object cli refers to? */
/**
* Consider the following code:
* CommandLineInterface cli = new DummyShell();
*
* In which class is the object cli refers to?
*/
static final String q2 = "";
/** True or false: CommandLineInterface is both a type and an interface. */
/**
* Consider the following code:
* CommandLineInterface cli = new DummyShell();
*
* true or false: CommandLineInterface is both a type and an interface.
*/
static final Boolean q3 = null;
/** True or false: DummyShell is both a class and a type. */
/**
* Consider the following code:
* CommandLineInterface cli = new DummyShell();
*
* true or false: DummyShell is both a class and a type.
*/
static final Boolean q4 = null;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment