Skip to content

Commit 90ba46d

Browse files
committed
[GR-13139] Add posix.get_terminal_size.
PullRequest: graalpython/335
2 parents a5ad1fe + 541ee3e commit 90ba46d

File tree

7 files changed

+143
-1
lines changed

7 files changed

+143
-1
lines changed

graalpython/com.oracle.graal.python.shell/src/com/oracle/graal/python/shell/ConsoleHandler.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,4 +109,14 @@ public int read() throws IOException {
109109
}
110110
};
111111
}
112+
113+
public int getTerminalWidth() {
114+
// deafult value
115+
return 80;
116+
}
117+
118+
public int getTerminalHeight() {
119+
// default value
120+
return 25;
121+
}
112122
}

graalpython/com.oracle.graal.python.shell/src/com/oracle/graal/python/shell/GraalPythonMain.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,8 @@ protected void launch(Builder contextBuilder) {
247247

248248
ConsoleHandler consoleHandler = createConsoleHandler(System.in, System.out);
249249
contextBuilder.arguments(getLanguageId(), programArgs.toArray(new String[0])).in(consoleHandler.createInputStream());
250+
contextBuilder.option("python.TerminalWidth", Integer.toString(consoleHandler.getTerminalWidth()));
251+
contextBuilder.option("python.TerminalHeight", Integer.toString(consoleHandler.getTerminalHeight()));
250252

251253
int rc = 1;
252254
try (Context context = contextBuilder.build()) {

graalpython/com.oracle.graal.python.shell/src/com/oracle/graal/python/shell/JLineConsoleHandler.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,4 +268,15 @@ public String[] getHistory() {
268268
}
269269
return result;
270270
}
271+
272+
@Override
273+
public int getTerminalHeight() {
274+
return console.getTerminal().getHeight();
275+
}
276+
277+
@Override
278+
public int getTerminalWidth() {
279+
return console.getTerminal().getWidth();
280+
}
281+
271282
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,11 +93,14 @@
9393
import com.oracle.graal.python.nodes.function.PythonBuiltinNode;
9494
import com.oracle.graal.python.nodes.function.builtins.PythonBinaryBuiltinNode;
9595
import com.oracle.graal.python.nodes.function.builtins.PythonTernaryBuiltinNode;
96+
import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode;
9697
import com.oracle.graal.python.nodes.truffle.PythonArithmeticTypes;
9798
import com.oracle.graal.python.nodes.util.CastToIndexNode;
99+
import com.oracle.graal.python.nodes.util.CastToIntegerFromIntNode;
98100
import com.oracle.graal.python.runtime.PosixResources;
99101
import com.oracle.graal.python.runtime.PythonContext;
100102
import com.oracle.graal.python.runtime.PythonCore;
103+
import com.oracle.graal.python.runtime.PythonOptions;
101104
import com.oracle.graal.python.runtime.exception.PException;
102105
import com.oracle.graal.python.runtime.exception.PythonErrorType;
103106
import com.oracle.graal.python.runtime.exception.PythonExitException;
@@ -1625,4 +1628,98 @@ int getAndSetUmask(int umask) {
16251628
}
16261629
}
16271630
}
1631+
1632+
@Builtin(name = "get_terminal_size", maxNumOfPositionalArgs = 1)
1633+
@GenerateNodeFactory
1634+
abstract static class GetTerminalSizeNode extends PythonUnaryBuiltinNode {
1635+
private final static String ERROR_MESSAGE = "[Errno 9] Bad file descriptor";
1636+
1637+
@Child private CastToIntegerFromIntNode castIntNode;
1638+
@Child private GetTerminalSizeNode recursiveNode;
1639+
1640+
@CompilationFinal private ConditionProfile errorProfile;
1641+
@CompilationFinal private ConditionProfile overflowProfile;
1642+
1643+
private CastToIntegerFromIntNode getCastIntNode() {
1644+
if (castIntNode == null) {
1645+
CompilerDirectives.transferToInterpreterAndInvalidate();
1646+
castIntNode = insert(CastToIntegerFromIntNode.create(val -> {
1647+
throw raise(PythonBuiltinClassType.TypeError, "an integer is required (got type %p)", val);
1648+
}));
1649+
}
1650+
return castIntNode;
1651+
}
1652+
1653+
private ConditionProfile getErrorProfile() {
1654+
if (errorProfile == null) {
1655+
CompilerDirectives.transferToInterpreterAndInvalidate();
1656+
errorProfile = ConditionProfile.createBinaryProfile();
1657+
}
1658+
return errorProfile;
1659+
}
1660+
1661+
private ConditionProfile getOverflowProfile() {
1662+
if (overflowProfile == null) {
1663+
CompilerDirectives.transferToInterpreterAndInvalidate();
1664+
overflowProfile = ConditionProfile.createBinaryProfile();
1665+
}
1666+
return overflowProfile;
1667+
}
1668+
1669+
@Specialization(guards = "isNone(fd)")
1670+
PTuple getTerminalSize(@SuppressWarnings("unused") PNone fd) {
1671+
if (getErrorProfile().profile(getContext().getResources().getFileChannel(0) == null)) {
1672+
throw raise(OSError, ERROR_MESSAGE);
1673+
}
1674+
return factory().createTuple(new Object[]{PythonOptions.getTerminalWidth(), PythonOptions.getTerminalHeight()});
1675+
}
1676+
1677+
@Specialization
1678+
PTuple getTerminalSize(int fd) {
1679+
if (getErrorProfile().profile(getContext().getResources().getFileChannel(fd) == null)) {
1680+
throw raise(OSError, ERROR_MESSAGE);
1681+
}
1682+
return factory().createTuple(new Object[]{PythonOptions.getTerminalWidth(), PythonOptions.getTerminalHeight()});
1683+
}
1684+
1685+
@Specialization
1686+
PTuple getTerminalSize(long fd) {
1687+
if (getOverflowProfile().profile(Integer.MIN_VALUE > fd || fd > Integer.MAX_VALUE)) {
1688+
raise(PythonErrorType.OverflowError, "Python int too large to convert to C long");
1689+
}
1690+
if (getErrorProfile().profile(getContext().getResources().getFileChannel((int) fd) == null)) {
1691+
throw raise(OSError, "[Errno 9] Bad file descriptor");
1692+
}
1693+
return factory().createTuple(new Object[]{PythonOptions.getTerminalWidth(), PythonOptions.getTerminalHeight()});
1694+
}
1695+
1696+
@Specialization
1697+
@TruffleBoundary
1698+
PTuple getTerminalSize(PInt fd) {
1699+
int value;
1700+
try {
1701+
value = fd.intValueExact();
1702+
if (getContext().getResources().getFileChannel(value) == null) {
1703+
throw raise(OSError, ERROR_MESSAGE);
1704+
}
1705+
} catch (ArithmeticException e) {
1706+
throw raise(PythonErrorType.OverflowError, "Python int too large to convert to C long");
1707+
}
1708+
return factory().createTuple(new Object[]{PythonOptions.getTerminalWidth(), PythonOptions.getTerminalHeight()});
1709+
}
1710+
1711+
@Fallback
1712+
Object getTerminalSize(Object fd) {
1713+
Object value = getCastIntNode().execute(fd);
1714+
if (recursiveNode == null) {
1715+
CompilerDirectives.transferToInterpreterAndInvalidate();
1716+
recursiveNode = create();
1717+
}
1718+
return recursiveNode.execute(value);
1719+
}
1720+
1721+
protected GetTerminalSizeNode create() {
1722+
return PosixModuleBuiltinsFactory.GetTerminalSizeNodeFactory.create();
1723+
}
1724+
}
16281725
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixResources.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ public Channel getFileChannel(int fd, ValueProfile classProfile) {
9494

9595
@TruffleBoundary(allowInlining = true)
9696
public Channel getFileChannel(int fd) {
97-
if (files.size() > fd) {
97+
if (files.size() > fd && fd >= 0) {
9898
return files.get(fd);
9999
}
100100
return null;

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonOptions.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,12 @@ private PythonOptions() {
119119
@Option(category = OptionCategory.EXPERT, help = "Enable forced splitting (of builtins). Default true.") //
120120
public static final OptionKey<Boolean> EnableForcedSplits = new OptionKey<>(true);
121121

122+
@Option(category = OptionCategory.EXPERT, help = "") //
123+
public static final OptionKey<Integer> TerminalWidth = new OptionKey<>(80);
124+
125+
@Option(category = OptionCategory.EXPERT, help = "") //
126+
public static final OptionKey<Integer> TerminalHeight = new OptionKey<>(25);
127+
122128
public static OptionDescriptors createDescriptors() {
123129
return new PythonOptionsOptionDescriptors();
124130
}
@@ -170,4 +176,12 @@ public static boolean isWithThread() {
170176
public static boolean getEnableForcedSplits() {
171177
return getOption(PythonLanguage.getContextRef().get(), EnableForcedSplits);
172178
}
179+
180+
public static int getTerminalHeight() {
181+
return getOption(PythonLanguage.getContextRef().get(), TerminalHeight);
182+
}
183+
184+
public static int getTerminalWidth() {
185+
return getOption(PythonLanguage.getContextRef().get(), TerminalWidth);
186+
}
173187
}

graalpython/lib-graalpython/posix.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,3 +135,11 @@ def uname():
135135

136136

137137
error = OSError
138+
139+
terminal_size = make_named_tuple_class("os.terminal_size", ["columns", "lines"])
140+
141+
old_get_terminal_size = get_terminal_size
142+
143+
@__builtin__
144+
def get_terminal_size(fd = None):
145+
return terminal_size(old_get_terminal_size(fd))

0 commit comments

Comments
 (0)